线程
如何证明多线程?
首先我们需要知道可能有哪些线程,哪段代码是属于哪个线程执行,这个区分了才好证明。而且我们证明需要有大量的数据,这样才能体现出效果。
finalize方法的调用可能是垃圾回收器线程来调用的,如果是则运行该代码有两个线程,那么一定会产生两个线程交替运行的结果(多次尝试),如果没有垃圾回收器线程,那么这个方法的调用就得老老实实地按照顺序接受main方法的安排。
public class Test1 { public static void main(String[] agrs) { for(int i=0;i<1000000;i++) new my(); for(int i=0;i<10000;i++) System.out.println("A:我是属于main线程的"); } } class my{ @Override public void finalize() { // TODO Auto-generated method stub System.out.println("B:我是属于垃圾回收器线程的"); } }
结果(选取有代表性的一段):
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
A:我是属于main线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
B:我是属于垃圾回收器线程的
线程的理解
先定义一个人,就是你自己,你有1000句话跟三个人说(a,b,c),如果你不支持线程,也就是无法跟一个人说话,还没说完就跟另一个人说的技能,那么你说话的顺序将是一条线,先将对a说的话说完,再将对b说的话说完,然后完成对c说的话。如果你支持多线程,那么跟a说几句话之后,这时候b过来插话,你就停止跟a的交流,去跟b说话,跟b说到一半,a又过来插话,于是完成对a的话,再完成对b的话,最后c因为没有插话,还是按照你自己的定义,最后完成c的话。这就有两个线程,一个是自己原本定义好的,第二个那就跟b说话的线程了。
自己建一个线程,让某些方法不受main线程约束
自己定义的线程就是上面所说的,将跟b的交流定义成一个线程类,允许b插话,如果将跟c的交流也定义成一个线程类,那么c也能插话了,b和c就打破了本有的规则,可以提前跟你说会话。(争着说话一样,插话的交流都是这样。没有确定性)(不过最后a可能很强大,b和c一点话都插不上)
public class Test2 { public static void main(String[] agrs) { for(int i=0;i<10000;i++) System.out.println("A:main"); Mytest m=new Mytest(); m.start(); } } class Mytest extends Thread{ public void run() { for(int i=0;i<10000;i++) System.out.println("B:我自己的线程,不受main线程约束"); } }
public class Test2 { public static void main(String[] agrs) { for(int i=0;i<10000;i++) System.out.println("A:main"); Mytest m=new Mytest(); new Thread(m).start(); } } class Mytest implements Runnable{ public void run() { for(int i=0;i<10000;i++) System.out.println("B:我自己的线程,不受main线程约束"); } }
线程的方法
String getName()
获取线程名
void setName(String name)
设置线程名
static Thread currentThread()
该方法必须写在线程代码里面,写在别的线程程序里面就是显示别的线程了(主要用于实现runnable接口的那种线程里面)
static void sleep(long millis)
你会发现输出的结果是一秒输出一个
public class Test3 { public static void main(String[] agrs) throws InterruptedException { System.out.println("nihao"); Thread.sleep(1000); System.out.println("nihao"); Thread.sleep(1000); System.out.println("nihao"); Thread.sleep(1000); System.out.println("nihao"); Thread.sleep(1000); System.out.println("nihao"); Thread.sleep(1000); System.out.println("nihao"); Thread.sleep(1000); } }
给某个线程加这个方法,可以让有这个方法的线程被最后选择。
void setDaemon(boolean on)
设置这个方法的线程的生命受到非守护线程的影响,当非守护线程生命完了之后,守护线程(设置了该方法的线程)就会挂掉。
void join()
调用该方法的线程是插入线程,当别的线程在执行时,插入该方法,那么调用该方法的线程就会先执行完。
void join(long millis)
设置允许进程插队的时间
tatic void yield()
线程让出cpu的方法(还是有不确定性)
void setPriority(int newPriority)
设置线程优先级
代码的同步
在使用多线程的同时也有弊端,当一个线程还没完成它的整体工作,就调换到另一个线程(比如你在跟a说话的同时,b过来插话,这时候如果b插上话了,而且当跟a正说“从前。。。。。”,一个完整的话还没说完就会让谈话不愉快)我们要做的就是找到属于一个完整的不可分割的代码块,用synchronized方法传入任何对象锁起来。(传入的对象必须是同一个对象)(同步代码块)
还可以用同步方法的方式锁起来。
线程安全问题
当自己只有一句话跟a,b,c,d说时,你请求跟a说话,a说等一分钟后再说,这时候你还有一句话没说出去,请求跟b说话,b又说等一分钟后再说,于是请求跟c说话,跟c说完之后,a和b又跑过来跟自己说话,程序停止,于是你会发现自己明明说只说一句话的,最后说了三句话。跟期望不符合。于是我们要告诉自己,必须等跟a交流完之后再进行别的,这就没有问题了。将执行的代码块锁起来,关键点是多个线程对象必须用同一把锁才有效。
死锁问题
两个线程的代码块都上了锁,而且一个代码块a里面嵌套了另一把锁,但是这个锁的打开需要等待代码块b锁的打开,但是b代码块里面又嵌套了a中使用的锁,就这样我等你,你等我,程序就停在那了。
线程的通信
当程序有多个线程时,我们一般都很难控制它们谁先执行,谁后执行,怎么样交替执行。于是通信的作用就在于此。
public class Test4 { public static void main(String[] agrs) { final Mytest1 my=new Mytest1(); new Thread() { public void run() { while(true) { try { my.m1(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { my.m2(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }.start(); } } class Mytest1 { private int flag=1; public void m1() throws InterruptedException { synchronized(this) { if(flag!=1) { this.wait(); } System.out.println("B"); flag=2; this.notify(); } } public void m2() throws InterruptedException { synchronized(this) { if(flag!=2) { this.wait(); } System.out.println("A"); flag=1; this.notify(); //随机唤醒某个线程 } } }
可以看到交替运行
三个线程的交替运行
public class Test5 { public static void main(String[] agrs) { final Mytest5 my=new Mytest5(); new Thread() { public void run() { while(true) { try { my.m1(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { my.m2(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { my.m3(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }.start(); } } class Mytest5 { private int flag=1; public void m1() throws InterruptedException { synchronized(this) { while(flag!=1) { this.wait(); } System.out.println("A"); flag=2; this.notifyAll(); } } public void m2() throws InterruptedException { synchronized(this) { while(flag!=2) { this.wait(); } System.out.println("B"); flag=3; this.notifyAll(); } } public void m3() throws InterruptedException { synchronized(this) { while(flag!=3) { this.wait(); } System.out.println("c"); flag=1; this.notifyAll(); } } }
互斥锁和通信
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Test6 { public static void main(String[] agrs) { final Mytest6 my=new Mytest6(); new Thread() { public void run() { while(true) { try { my.m1(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { my.m2(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { my.m3(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }.start(); } } class Mytest6 { private ReentrantLock r=new ReentrantLock(); private Condition c1=r.newCondition(); private Condition c2=r.newCondition(); private Condition c3=r.newCondition(); private int flag=1; public void m1() throws InterruptedException { r.lock(); if(flag!=1) { c1.wait(); } System.out.println("A"); flag=2; c2.signal(); r.unlock(); } public void m2() throws InterruptedException { r.lock(); if(flag!=2) { c2.await(); } System.out.println("B"); flag=3; c3.signal(); r.unlock(); } public void m3() throws InterruptedException { r.lock(); if(flag!=3) { c3.wait(); } System.out.println("c"); flag=1; c1.signal(); r.unlock(); } }