Thread线程的方法用法,有代码例子,简单易懂

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

/**

* 程序 :

* 就是指我们写的保存硬盘当中的静态文件,叫程序

* 进程:

* 就是程序被加载进内存,准备或者正在运行时,就叫进程

* 线程 :

* 就是程序中不同的执行路径

*

* 线程 :

* 当我们程序开始执行的时候,就是java中main()方法开始执行,在栈内存中开辟main()栈帧的时候,就是开启了一个线程

* 一个线程就是一个栈及其里面的链式栈帧,一个栈帧就对应一个方法.

*

*/

☆☆☆☆ 重点 ☆☆☆☆ !

创建一个新的线程有两种方式,

但是启动一个线程,只有一种方式(唯一的一种);

//三个要点 :

线程的定义;

线程的启动;

线程开启之后;

// 线程的定义 :

程序不同的执行路径,从代码角度来讲,线程就是一个类,从内存角度来讲,线程就是一个栈和链式栈帧

// 线程必须要先启动 :

start();//成员方法

// 一旦开启多线程 :

这个时候,说代码是从左到右,从上往下执行这句话就不准确了,因为,我们开启了两个线程,在每个线程的内部,仍然是从上到下,从左到右,但是线程之间的代码,没有固定的先后顺序,他们执行的先后顺序,是不确定的,和CPU,操作系统,和我们自己的设定,都相关

Thread :

//创建线程

创建一个新的线程,有两个方式 :

//第一种 :

第1步 : 继承java.lang.Thread;这个类

第2步 : 重写run()方法,为什么要重写?因为run()就相当于新线程的main()方法,就是程序执行的起点和终点;

//创建了线程,不启动,不能用 : start();

//开启线程 :

Thread t = new 子类名();

t.start();//就开启线程了

Runnable:

//第二种 :

第1步 : 实现java.lang.Reunnable接口

第2步 : 实现接口的run()方法;

//开启线程 :

1 Thread t = new Thread(new 子类名());

t.start();//开启线程

2 Runnable(或者是子类名) r = new 子类名();//多态

Thread t = new Thread(r);

t.start();//开启线程

Thread_start:

start();//启动线程(唯一的方法) 默认会去调用该线程的run()方法 成员方法

启动一个线程 : 只能是Thread类中的start()方法;

currentThread:

currentThread();//获取当前线程的内存地址 静态方法,类名调用就行 对象名也行,底层会默认转换为类名

Thread.currentThread();//获取当前线程的内存地址(在哪个线程写的,Thread就是哪个线程)

setName:

setName();//给线程取名字,不设置默认是Thread-0,依次累加

Thread t1 = new 子类名();//默认的名字是在new的时候取得 Thread-0

t1.setName("t1");//现在,线程名字就改为t1了

t1.start();

getName:

getName();//获得当前线程的名字 成员方法

Thread.currentThread().getName();//因为getName()是成员方法,所以想调用这个方法,要先获得当前线程的内存地址吧,就是Thread.currentThread();

sleep:

sleep : 在那个线程写的,就锁定那个线程,和 用哪个线程的引用调用sleep()没有关系(因为底层也会默认转成类名)

//让某个线程休眠 可以直接类名调用就行了

//线程中,加了sleep(),就必须抛异常或者捕捉异常

sleep();//让当前线程睡眠指定的毫秒数 是静态方法 类名调用就行

Thread.sleep(1000);//让该线程睡眠 1 秒;写在那个线程,就睡眠那个线程

setPRiority:

setPriority();//设置线程的优先级 成员方法

线程的默认优先级 :

//子线程默认继承父类的线程优先级

java中线程的优先级有0-10 11个级别

win当中是1-7 7个优先级

MIN_PRIORITY : 1 //最低

MAX_PRIORITY : 10 //最大

NORM_PRIORITY : 5 //正常

Thread.currentThread().setPriority(Thread.MIN_PRIORITY);//(设置当前线程的优先级)成员方法要用对象引用去调用吧.先获取当前线程的内存地址,调用setPriority();去设置优先级 这里设置的为 1 最低的 不设置默认为 5 NORM_PRIORITY

Thread t = new 子类名();

t.setPriority(Thread.MAX_PRIORITY);//这和上面那个是一样的,只不过上面那个,写在哪,就设置那个线程的优先级,这个是设置指定的那个线程的优先级

//唤醒休眠的两种方法 :

1 Interrup();//异常唤醒,需要捕捉和抛异常

2 while();//循环

Interrup:

Interrup();//这种方式唤醒,一定要try...catch..处理异常或者是throws抛异常

//异常类型 : InterruptedException

Thread t = new 子类名();//这种是继承Thread并覆写run()方法的,这种创建线程方式

Thread t = new Thread(new 子类名());//这种是实现Runnable接口,并实现run()方法的,这种创建线程方式

t.start();//启动线程

t.interrupt();//强行唤醒(异常唤醒)

while:

用while循环(或者别的循环,加if),

需要强行唤醒,就在主线线程设置 引用(对象名).run=false;就行了

boolean run = true;//成员变量

int i =0;//成员变量

public void run(){//线程类的run()方法

while(run){//循环 这里如果为true 就会一直循环(死循环把)

i++;

MIN_PRIORITY : 1

try{

Thread.sleep(1000);

}catch(Exception e){

e.printStackTrace();

}

System.out.println( Thread.currentThread().getName()+"--->"+i );

}

}

join:

join();//也就是线程的合并,把两个线程,合并成一个线程(成了单线程) 成员方法

等着当前线程执行完毕,然后再在本线程后面继续往下执行,当前行以后,所有的main线程的代码,都必须等着这个线程执行完毕以后再执行,相当于这个线程和main线程合并,变为单线程程序,又是从上往下执行

Thread t = new 子类名();

t.start();//启动线程

t.join();//这行一下的main线程的代码,都必须等待t执行完,才能继续执行

yield:

yield();//静态方法 可以直接类名调用,让当前线程让位一次(只跟同级)

1 这是一个静态方法,一维这:即使用对象调用他,也会在底层转换为类名调用,停掉的也还是当前所在的线程,也就是说在那个类中调用,就停止那个线程

2 给同一个优先级的线程让位,不同的优先级,不让位

3 和sleep()方法相同,那个线程调用就停止那和累的线程,但是没有时间,不固定,只是让出当前这个时间片,下一个时间片让不让,另说

Thread.yield();//跟同级线程,让位一次 写在哪,哪个就让位一次

synchronized: :

synchronized : 并不是往对象里面加锁,锁是每个对象都有的属性,synchronized只是锁上了这把锁,是个持续的动作而已

synchronized 是一个修饰符,修饰的方法,等于是给方法加了一把钥匙,当一个线程执行这个方法的时候,别的所有线程都不能再去执行这个方法,和用synchronized修饰的方法,一个方法锁住,所有用synchronized修饰的方法都会锁上,但是没有用synchronized修饰的方法,可以访问//目的就是让数据同步

//线程同步本质 :

当多个线程(服务,任务),操作同一个数据的时候,保证数据一致,本质就是数据同步,是一种数据安全机制

这种机制,操作上更多是从数据上来保护的

//异步编程模型 :

线程是完全独立的,谁的运行也不会受到别的线程的影响

//同步编程模型 :

线程间不是独立的,互相间有影响的,某些线程必须单独完成任务以后,才能 够让别的线程执行(为什么?)

//同步的原因 :

1 同步是指数据的同步,为了数据安全,必须要等某个线程对数据操作完成以后,在引入别的线程进行操作

同步机制,某种程度是多线程编程变成了单线程

2 同步的环境

1 必须多线程

2 多个线程有同时操作同一个数据的可能性

3 主要就是涉及数据更改的操作

线程同步是数据的概念

//方法 : 锁定,锁定是一个逻辑上的概念,是为了保证同步的手段

//方发锁 : 按照封装性,根本不可能再是直接就能对数据进行操作只能通过方法进行操作

//对象锁 : 堆内存,只要一加锁,谁也进不来

//类锁 : 更大级别的

只要加了 synchronized 修饰的成员方法(静态方法),是多个线程不可以用加了synchronized的方法同时访问这个对象(类)

同一个方法互斥,不同的方法也互斥

//静态方法声明 :

又称为类锁;

public synchronized static void m1(){

System.out.println( "不管谁被锁,我都会被锁,他解开,我才解开" );

}

public synchronized static void m2(){

System.out.println( "不管谁被锁,我都会被锁,它解开,我才解开" );

}

public static void m3(){

System.out.println( "别人锁不锁,干我何事" );

}

比如我有两个线程,t1和t2把

t1调用了m1();/*就会锁住*/ t2就不能调用m1()和m2();/*m2()也会被锁住*/只能调用m3();//因为m3()没有用synchronized修饰

//成员方法声明 :

又称对象锁

前提是/*对象*/必须是同一个对象

public synchronized void m1(){

System.out.println( "不管谁被锁,我都会被锁,他解开,我才解开" );

}

public synchronized void m2(){

System.out.println( "不管谁被锁,我都会被锁,它解开,我才解开" );

}

public void m3(){

System.out.println( "别人锁不锁,干我何事" );

}

比如我有两个线程,t1和t2把//并且t1线程和t2线程都是同一个对象

t1调用了m1();/*就会锁住*/ t2就不能调用m1()和m2();/*m2()也会被锁住*/只能调用m3();//因为m3()没有用synchronized修饰

setDaemon :

setDaemon();//设置守护线程(兜底线程)

只要主线程执行完毕,不管守护线程执行了多少,执行到哪,都不会在执行,也跟着死去,但是跟主线程晚结束一下,

//活,他先活,死,他先死(要么怎么守护,守护线程,先活,后死)

Thread t1 = new 子类名();//创建一个线程把,用的是继承的方式

t1.setDaemon(true);//里面是布尔型 true/false 把当前线程设置为守护线程

t1.start();//启动t1线程把

//如果我守护线程里面有个死循环(就是不会结束的那种),但是,只要主线程执行完毕,守护线程也会跟着结束

Timer:

1 创建一个定时器(Timer)

2 创建一个执行定时器任务的类,这个类必须继承于 TimerTask 这个类,并且,必须覆写 TimerTask 类中的 run(),方法.(TimerTask)

3 用 Timer 类里面的 schedule()方法,分配并执行定时器任务(schedule)

Timer :

Timer t = new Timer();//创建一个定时器,并且调用Timer类里面的 schedule()方法,分配执行的任务

TimerTask :

class 类名 extends TimerTask{

public void run(){

System.out.println( new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()) );//获取当前时间,输出

}

}

Date :

Date d = new Date();//获取当前的时间

String d1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(d);//以这种形式,输出当前时间d

schedule :

schedule();//Timer里面的schedule(要执行任务的类对象 , 起始的时间 , 任务执行间隔的毫秒数 );//循环执行方法,默认调用run()方法

t.schedule(

new 类名(),/*执行定时器任务的类的对象*/

new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").parse("2015-09-10 14:48:00 000"),/*其实时间(从什么时间,开始执行)*/

1000*3)/*执行任务的间隔时间*/;

synchronized:

//死锁

synchronized : 并不是往对象里面加锁,锁是每个对象都有的属性,synchronized只是锁上了这把锁,是个持续的动作而已

死锁 : 死锁就是大家都访问不了的状态;

原理 :

1 两个线程,两个对象

2 先后 嵌套 锁定 执行 两个对象(先锁定第一个对象,再嵌套锁定第二个对象)

3 先后 嵌套 锁定 执行 两个对象(先锁定第二个对象,再嵌套锁定第一个对象)

4 在第一个线程执行过程中,执行到第二个对象的时候,发现第二个被锁死了,也只能等待

5 第二个线程执行过程中,执行到第一个对象的时候,发现第一个被锁死了,也只能等待

public class Thread线程{

public static void main(String[] args){

//这里我用Object是因为不用再写实体类了,这个类可以自己写

Object o1 = new Object();//第一个对象

Object o2 = new Object();//第二个对象

Thread t1 = new Thread(new T1(o1,o2));//第一个线程(调用的是有参构造把)

Thread t2 = new Thread(new T2(o1,o2));//第二个线程

t1.start();//启动线程

t2.start();//启动线程

}

}

class T1 implements Runnable{//线程类吧

Object o1;//成员变量 这里用于接收实参传进来的Object的对象引用(实体类用的那个类,这里就要用那个类去接吧)

Object o2;

T1(Object o1,Object o2){//有参构造

this.o1 = o1;//赋值

this.o2 = o2;

}

public void run(){//覆写的run()方法

synchronized(o1){//锁定第一个对象 (o1)

try{

Thread.sleep(1000);//不睡眠一秒,有时候不死锁,睡眠一秒,百分百死锁(因为如果是我t1线程执行完了,t2线程在开始执行的呢?那就不是死锁了吧,这样,t1到这停一秒,一秒足够t2也走的o2的那个对象那里,所以就死锁了,都在等待)

}catch(Exception e){

e.printStackTrace();

}

synchronized(o2){//在锁定第一个对象(o1)中 嵌套锁定第二个对象(o2)

System.out.println( "t1" );//如果,t1执行完成了,就会输出 但是如果死锁了,t1就进不来吧 就不会输出

}

}

}

}

class T2 implements Runnable{//创建线程类

Object o1;//成员变量 这里用于接收实参传进来的Object的对象引用(实体类用的那个类,这里就要用那个类去接吧)

Object o2;

T2(Object o1, Object o2){//和上面一样,不懂就看上面的注释

this.o1 = o1;

this.o2 = o2;

}

public void run(){

synchronized(o2){//t1线程先锁定的o1,我这里如果先锁定o2,没有关系吧,t1能进o1,但是我也能进o2 ,因为是不同的对象,但是我如果再想进o1,是不是就进不去了(因为t1进去就锁了)

try{

Thread.sleep(1000);//这个也停一秒,就是当t2进来o2这个对象,并锁定了,t1也肯定就能进去o1这个对象,并也锁定了,现在就开始进入等待了吧,就是死锁

}catch(Exception e){

e.printStackTrace();

}

synchronized(o1){//嵌套锁定o1

System.out.println( "t2" );

}

}

}

}

wait:

wait是 Object 类的方法 ,不是Thread中的方法 Thread中wait也是继承于 Object

注意 : 如果该对象没有被锁定,则调用wait方法,就会报错,即只有在同步方法或者同步代码块中(也就是某线程访问,用 synchronized 修饰的方法之后)才可以调用wait方法,notify,notifyAll同理

this.wait();不是让当前对象wait,而是让当前锁定this对象的线程wait,同时 释放对this的锁定

//wait()和sleep()的区别 :

wait : wait()会把锁打开,让别的线程进来,并且自身进入睡眠,只能等待唤醒,如果不唤醒,会一直休眠(并且,当前线程wait()下面的代码不会执行,只能等待唤醒,才能执行)

sleep : sleep()就算设置了休眠,但是锁也不会打开,别的线程也进不来,并且可以唤醒,但是如果不唤醒,到了指定的睡眠时间,自身也会唤醒(并且,当前线程sleep()下面的代码不会执行,只能等待唤醒,才能执行)

this.wait();//如果这个休眠,会打开锁,让别的线程执行

System.out.println( "我在睡眠" );//不会执行,如果没有线程唤醒,永远不会执行,会永远睡眠

Thread.sleep(5000);//睡眠5秒,并且不会打开锁,别的线程也得等着,一样进不来

System.out.println( "我快唤醒了" );//如果没有线程唤醒当前睡眠的线程,那么,5秒后,自动醒,一样会输出

notify:

notify是Object 类的方法 ,不是Thread中的方法 Thread中notify也是继承自Object

注意 : 如果该对象没有被锁定,则调用wait方法,就会报错,即只有在同步方法或者同步代码块中(也就是某线程访问,用 synchronized 修饰的方法之后)才可以调用wait方法,notify,notifyAll同理

notify() : 随机唤醒一个在该对象上睡眠的某一个线程(一般都是谁先睡眠,谁先醒,具体不知道,是系统随机唤醒的),并且,没有让自身进入睡眠状态

this.notify();//随机唤醒一个在该对象上睡眠的线程

System.out.println("我能输出" );//我能输出,因为上面只是唤醒了一个线程,并没有让自身进入睡眠状态

notifyAll:

notifyAll是Object 类的方法 ,不是Thread中的方法 Thread中notifyAll也是继承自Object

注意 : 如果该对象没有被锁定,则调用wait方法,就会报错,即只有在同步方法或者同步代码块中(也就是某线程访问,用 synchronized 修饰的方法之后)才可以调用wait方法,notify,notifyAll同理

notifyAll() : 唤醒在该对象上,所有等待的线程,并且,没有让自身进入睡眠状态

this.notifyAll();//唤醒所有在该对象上睡眠的线程

System.out.println( "我能输出" );//我能输出,因为上面只是唤醒了所有线程,并没有让自身进入睡眠状态

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航