线程学习笔记1

来源:互联网 发布:淘宝老客户回访率查询 编辑:程序博客网 时间:2024/06/06 18:23

1、线程是一个程序内部不同的执行路径。

2、线程和进程的区别

每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。

线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器,线程切换的开销小。

多进程:在操作系统中可能同时运行多个任务(程序)

多线程:在同一应用程序中有多个顺序流同时执行。

···什么叫进程,机器上的一个.class文件,一个.exe文件,就是一个程序类似于。

代码放在内存中的code segment区域中,并没有开始执行,这个时候说明一个进程准备开始执行了,进程是一个静态的概率,平时所说的进程的执行,指的是进程里面

的main方法开始执行了。

···什么叫线程,一个程序中不同的执行路径,说白了就是该进程中的不同的任务。

···(单核/单CPU)在同一个时间点上,你的机器上只运行一个线程在运行。

java的线程是通过java.lang.Thread类来实现的。或是实现Runnable接口。

public void start(){}方法启动线程,不是方法的调用,public void run()方法是具体线程要执行什么东西。

其实Thread方法已经实现了Runnable接口,Thread的构造方法中有传入Runnable接口的引用,这其中就有多态的存在。我们其实在该构造方法中传入的是

实现Runnable接口的类的对象的引用。

Thread()
          分配新的 Thread 对象。Thread(Runnable target)
          分配新的 Thread 对象。Thread(Runnable target,String name)
          分配新的 Thread 对象。Thread(String name)
          分配新的 Thread 对象。(相当于给当前这个线程对象起了个名字。)Thread(ThreadGroup group,Runnable target)
          分配新的 Thread 对象。Thread(ThreadGroup group,Runnable target,String name)
          分配新的 Thread 对象,以便将target 作为其运行对象,将指定的name 作为其名称,并作为group 所引用的线程组的一员。Thread(ThreadGroup group,Runnable target,String name, long stackSize)
          分配新的 Thread 对象,以便将target 作为其运行对象,将指定的name 作为其名称,作为group 所引用的线程组的一员,并具有指定的堆栈尺寸Thread(ThreadGroup group,String name)
          分配新的 Thread 对象。java中并不是调用了start()方法就立刻开始执行该线程,只是让它处于就绪状态。就像上厕所一样,并不是说你来了你就一定要上,说不定厕所里还有别人正在蹲着

呢,CPU就像一个大厕所,Thread类中有一个方法叫做 isAlive(),判断线程是否是活着的状态,就绪、运行、阻塞都是活着的状态,只有在start()之前和终止是死亡

状态。


线程有优先级,通过getPriority()方法获取线程优先级,setPriority()方法设置线程优先级,上厕所不是你说上就上,你旁边还有你们县长在旁边也在等着上厕所呢,

那对不起,你们县长先上,你们你们县长优先级高。

Thread类还有一个sleep()方法,该方法是个静态方法,设置当前线程睡眠指定的毫秒数,还可以指定纳秒数,一般都是毫秒数就可以了。

调用sleep()方法,如果你强制打断它(调用interrupt()方法),肯定会抛出异常。就像正在睡觉时泼了一碰凉水。在那个线程中调用Thread.sleep()方法,就代表该线程

调用这个sleep()方法。

public final void stop();这个方法也是打断,但已经过时了,这个方法比interrupt()方法更加粗暴,直接一棒子打脑袋上了。

interrupt()方法至少还有一个自己执行抛出异常后的语句的机会,stop这个方法,比如打开一个文件再也关不上了。尽量不要让调用stop()方法。

join方法,合并某个线程,等着那个线程先执行完,然后才继续开始执行。例如在main主方法中,调用某个子线程的join()方法,这两个线程相当于合并,主方法就要

等到join()方法执行完毕后才继续开始执行。

yield()方法是先让出当前线程的CPU资源,是该线程从执行状态变为可执行状态,并不是说让出CPU以后就非要有别的线程来执行,它自己本身也是有机会得到执行的

线程的优先级,默认的优先级是5。这里我们所说的更高优先级并不一定是单单的只执行高优先级的,低优先级的也有机会得到执行。

Thread类的currentThread() 方法是返回的当前线程,不要以为返回一个对象。

线程同步是当两个线程访问同一个资源,如果处理不好的话所以会出现混乱,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。

synchronized锁,可以为几个语句加锁,

一、synchronized(this){

语句1;

语句2;

}

当一个线程执行到这个被锁定的语句块时,其它线程不可以对齐进行访问

二、public synchronized void add(){

语句1;

语句2;

}

在执行当前方法的过程中,锁定当前对象。

import java.util.*;public class SyncDemo implements Runnable{Timer time=new Timer();public static void main(String[] args){SyncDemo demo=new SyncDemo();Thread thread1=new Thread(demo);Thread thread2=new Thread(demo);thread1.setName("t1");thread2.setName("t2");thread1.start();thread2.start();}public void run(){time.add(Thread.currentThread().getName());}}class Timer{public static int num;public void add(String name){synchronized(this){num++;try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}//sleep()一下只是放大那个效果,当thread1访问这个资源被thread2打断了。System.out.println(name+"你是第一个"+num+"个");}}}

附上一篇线程同步的精讲博客

线程还有一个非常不好的问题,就是死锁。

A线程锁定了1对象,它还要锁定2对象,而B对象锁定了2对象,它还要锁定1对象,这就形成了死锁。企业面试有时会直接让你写一个死锁的程序。

public class DeadLockDemo implements Runnable{private static Object o1=new Object();private static Object o2=new Object();//这两个Object对象是属于整个类共享的,而不是属于某个对象。private int flag;public DeadLockDemo(int flag){this.flag=flag;}public void run(){System.out.println("flag="+flag);if(flag==0){synchronized(o1){try{Thread.sleep(2000);}catch(InterruptedException e){e.printStackTrace();}synchronized(o2){System.out.println("hello,I'm o");}}}if(flag==1){synchronized(o2){try{Thread.sleep(2000);}catch(InterruptedException e){e.printStackTrace();}synchronized(o1){System.out.println("hello,I'm 1");}}}}public static void main(String[] args){DeadLockDemo d1=new DeadLockDemo(0);DeadLockDemo d2=new DeadLockDemo(1);Thread thread1=new Thread(d1);Thread thread2=new Thread(d2);thread1.start();thread2.start();}}
public class TTDemo implements Runnable{private int b=100;public static void main(String[] args) throws InterruptedException{TTDemo tt=new TTDemo();Thread thread=new Thread(tt);thread.start();Thread.sleep(1000);System.out.println("haha");tt.m2();
}public synchronized void m1() throws InterruptedException{b+=1000;Thread.sleep(6000);b+=500;System.out.println("b="+b);}public void m2(){b=500;System.out.println(b);}public void run(){try{m1();}catch(InterruptedException e){e.printStackTrace();}}}

首先来分析一下上面代码的执行过程:

在main()方法中首先栈中分配一个引用,指向堆中实际new出来的对象

将该引用当做参数传递给Thread的构造方法,调用start()方法启动线程,线程中调用了m1()方法,m1()方法中将b的值改为1100

然后线程休眠休眠6秒,休眠时主线程1秒,然后输出一句话"haha",接下来该对象的引用直接调用m2()方法,将b的值改为500,然后输出

然后回到m1()方法,再将b的值改为1000,输出,线程结束,主线程结束。

被锁定的方法中,改变某个成员变量,另外一个方法可以引用该成员变量,在另外的线程中执行该方法。修改变量值。因此能改这个方法

你要是保护好某个对象的话,要考虑到别的线程可以任意访问那些没加锁的方法,并且可能对该对象产生影响。


在上面那个代码中,如果是将m2()方法也加锁的话,那么该类的对象就要等到thread线程执行结束才开始执行m2(),方法,我不由得开始怀疑

我们对一个实现了Runnable接口的类的两个或是两个以上的方法加锁,那么为该类创建一个对象的话,该对象调用其中的几个方法,那么就要等到每个

方法都执行依次执行完才能算是结束。所以说加锁是对该类的某个对象而言,该类可能有很多线程,以上的thread.start()启动一个线程,然后tt.m2()也是属于该对象的一个线程。

验证一下,在为方法m2()加锁之后:

public class TTDemo implements Runnable{private int b=100;public static void main(String[] args) throws InterruptedException{TTDemo tt=new TTDemo();Thread thread=new Thread(tt);thread.start();System.out.println("haha");tt.m2();System.out.println(tt.b);//TTDemo ttt=new TTDemo();//ttt.m2();}public synchronized void m1() throws InterruptedException{b+=1000;Thread.sleep(3000);System.out.println("b="+b);}public synchronized void m2() throws InterruptedException{b=2000;Thread.sleep(1000);System.out.println(b);}public void run(){try{m1();}catch(InterruptedException e){e.printStackTrace();}}}//问:非静态的方法可以存取静态的变量吗?//回答:当然可以。非静态方法不可以调用该类静态的方法或静态的变量。
这段代码线程thread执行完m1()方法后,该类的对象(引用为tt)才开始执行m2()方法。


那么如果要是在创建一个对象,去另外调用m2()方法,估计就互相不干扰了。

实验一下:

public class TTDemo implements Runnable{private int b=100;public static void main(String[] args) throws InterruptedException{TTDemo tt=new TTDemo();Thread thread=new Thread(tt);thread.start();/*System.out.println("haha");tt.m2();System.out.println(tt.b);*/TTDemo ttt=new TTDemo();ttt.m2();}public synchronized void m1() throws InterruptedException{b+=1000;Thread.sleep(3000);System.out.println("b="+b);}public synchronized void m2() throws InterruptedException{b=2000;Thread.sleep(1000);System.out.println(b);}public void run(){try{m1();}catch(InterruptedException e){e.printStackTrace();}}}//问:非静态的方法可以存取静态的变量吗?//回答:当然可以。非静态方法不可以调用该类静态的方法或静态的变量。
这里两个对象,成员变量b是非静态的,所以每个对象都有一个d变量,第二个对象想调用m2(),就调用m2()。如果成员变量b是静态的话,就将会产生影响。