1、调用Thread类可以操作线程。步骤是:调用thread类创建线程,复写run();方法,启动线程(调用run方法)。每次的结果都不同是因为CUP的使用权不确定。thread类中的run方法是用于存储线程的代码,同理,main方法是虚拟机要调用的代码的存储位置。run();和start();的区别是前者是创建新线程,后者仍旧是单线程。一个thread线程子类可以创建多个线程,多个子类也可以分别创建自己的子线程。
1 package pack; 2 3 public class Test1 4 { 5 public static void main(String[] args) 6 { 7 Thread1 t=new Thread1(); 8 t.start(); //开启Thread1线程 9 Thread1 tt=new Thread1(); 10 tt.start(); 11 12 Thread2 t1=new Thread2(); 13 t1.run(); //未开启Thread2线程,只是简单地调用,仍旧是单线程 14 15 for(long i=0;i<10;i++) 16 System.out.println("主线程:"+i); 17 18 Thread t2=new Thread(); 19 t2.start(); 20 } 21 } 22 class Thread1 extends Thread 23 { 24 public void run() //一个存储线程的空间 25 { 26 for(long i=0;i<10;i++) 27 System.out.println("自定义线程1:"+i); 28 } 29 } 30 class Thread2 extends Thread 31 { 32 public void run() 33 { 34 for(long i=0;i<10;i++) 35 System.out.println("自定义线程2:"+i); 36 } 37 }
2、线程分为5种状态:创建,运行,冻结,消亡和临时状态。其中,运行状态是具备有运行资格也有执行权的状态,冻结状态是放弃了执行资格,临时状态(阻塞状态)是具有运行资格但没有执行权,消亡状态是没有了运行资格程序结束。Thread类创建了线程对象是线程创建状态,用new关键字来实现;线程对象调用start方法后处于运行状态;运行状态的线程通过sleep(time)方法和wait方法放弃运行资格,时间到了或者用notify方法唤醒线程,使线程进入临时状态;临时状态都的线程具备有运行资格,临时状态和运行状态可以相互转化;运行态的线程也可以用stop方法或者因为run内的程序结束而进入消亡状态。
3、每一个线程都有自己的默认名称:Thread-编号,编号从0开始。currentThread()方法是获取当前线程对象。setName()是设置线程名称,getName();是获取线程名称。
4、Java还可以用runnable来定义线程。步骤是:定义一个runnable接口的子类,重写子类的run方法,创建一个thread类的子类,将runnable的子类对象作为实际参数传入thread子类中,调用Thread子类的start方法创建线程,执行run方法内的线程。
5、执行接口的类方法不能抛出异常,一般在方法内部用catch解决,如果要抛出就需要在定义接口的时候抛出异常。多线程安全问题产生的原因会是一个共享的数据被多个线程操作产生的错误。解决的一般办法是让一个线程执行完在执行另一个线程。java提供了专业的同步代码块来解决这个问题。synchronizedi(对象){要同步的代码块}。多个线程需要判断锁,比较消耗资源。同步的另一种方法是将同步修饰符synchronized放在函数上,形成同步函数。
1 package pack; 2 3 public class Test1 4 { 5 public static void main(String[] args) 6 { 7 Thread1 t=new Thread1(); 8 Thread t1=new Thread(t); 9 Thread t2=new Thread(t); 10 Thread t3=new Thread(t); 11 t1.start(); 12 t2.start(); 13 t3.start() ; 14 } 15 } 16 class Thread1 implements Runnable 17 { 18 private int tt=100; 19 /* 20 Object o=new Object(); 21 public void run() 22 { 23 while(true) 24 { 25 synchronized(o) 26 { 27 if(tt>0) 28 { 29 try{Thread.sleep(10);}catch(Exception e){} 30 System.out.println(Thread.currentThread().getName()+" "+tt--); 31 } 32 } 33 } 34 } 35 */ 36 public synchronized void run() 37 { 38 while(true) 39 { 40 if(tt>0) 41 { 42 try{Thread.sleep(10);}catch(Exception e){} 43 System.out.println(Thread.currentThread().getName()+" "+tt); 44 tt--; 45 } 46 } 47 } 48 }
说明:此程序虽然使用了同步修饰符synchronized,但它不是多线程。
6、同步函数的锁是this。如果同步函数被静态修饰后,锁不能是this了,因为静态中不能用this,静态同步函数的锁是该方法锁在类的字节码文件:类名.class。
1 package pack; 2 /* 3 * 总共有5000张票,设置三个窗口,也即三个线程,售票。 4 */ 5 public class Test1 6 { 7 public static void main(String[] args) 8 { 9 Thread1 t=new Thread1(); 10 Thread t1=new Thread(t); 11 Thread t2=new Thread(t); 12 Thread t3=new Thread(t); 13 t1.start(); 14 t2.start(); 15 t3.start(); 16 } 17 } 18 class Thread1 implements Runnable 19 { 20 private int tt=5000; 21 /* 22 * private static int tt=5000; //静态同步函数的锁是类class 23 //Object o=new Object(); 24 public void run() 25 { 26 while(true) 27 { 28 synchronized(Thread1.class) 29 { 30 if(tt>0) 31 { 32 try{Thread.sleep(10);}catch(Exception e){} 33 System.out.println(Thread.currentThread().getName()+" "+tt--); 34 } 35 } 36 } 37 } 38 */ 39 public void run() 40 { 41 while(true) 42 { 43 this.show(); //同步函数的锁是this 44 } 45 } 46 public synchronized void show() //单独把if语句拿出来,构造同步函数 47 { 48 if(tt>0) 49 { 50 try{Thread.sleep(10);}catch(Exception e){} 51 System.out.println(Thread.currentThread().getName()+" "+tt--); 52 } 53 } 54 }
7、死锁:通常的情况是同步中嵌套同步,而锁却不同。锁可以是任意对象。
1 package pack; 2 //create a deadlock programming 3 public class DeadLock 4 { 5 public static void main(String[] args) 6 { 7 Thread t=new Thread(new Test(true)); 8 Thread t1=new Thread(new Test(false)); 9 t.start(); 10 t1.start(); 11 } 12 } 13 14 class Test implements Runnable 15 { 16 private boolean flag; 17 Test(boolean flag) 18 { 19 this.flag=flag; 20 } 21 @Override 22 public void run() 23 { 24 // TODO Auto-generated method stub 25 if(flag) 26 { 27 synchronized(Lock.la) 28 { 29 System.out.println("la lock"); 30 synchronized(Lock.lb) 31 { 32 System.out.println("lb lock"); 33 } 34 } 35 } 36 else 37 { 38 synchronized(Lock.lb) 39 { 40 System.out.println("lb lock"); 41 synchronized(Lock.la) 42 { 43 System.out.println("la lock"); 44 } 45 } 46 } 47 } 48 } 49 class Lock 50 { 51 public static Object la=new Object(); 52 public static Object lb=new Object(); 53 }
8、线程间通信:多个线程共同操作一个资源,但操作方式不同。同步考虑多个线程是否是同一个锁,是否多个线程都用同步修饰符。wait,notify,notifyall方法都是只用在同步里,因为要对持有监视器(锁)的线程里操作,只有同步里才有锁。
以下是多线程低版本的jdk下的程序:
1 package pack; 2 //线程间的通信,创建两个线程和一个共享资源。其中一个线程为资源属性赋值,另一个线程输出资源属性值。 3 public class ThreadCommunication 4 { 5 public static void main(String[] args) 6 { 7 Resourse r=new Resourse(); 8 /* 9 Input i=new Input(r); 10 Output o=new Output(r); 11 Thread t1=new Thread(i); 12 Thread t2=new Thread(o); 13 t1.start(); 14 t2.start(); 15 */ 16 new Thread(new Input(r)).start(); 17 new Thread(new Output(r)).start(); 18 } 19 } 20 //多线程通信方法一 21 /* 22 //创建一个共享资源,人 23 class Resourse 24 { 25 String name; 26 String sex; 27 boolean b=true; 28 } 29 //创建一个为资源赋值的线程 30 class Input implements Runnable 31 { 32 private Resourse r; 33 Input(Resourse r) 34 { 35 this.r=r; 36 } 37 public void run() 38 { 39 int x=0; 40 while(true) 41 { 42 synchronized(r) //锁是Resourse类对象 43 { 44 while(r.b==true) 45 { 46 if(x==0) 47 { 48 r.name="Joe"; 49 r.sex="man"; 50 } 51 else 52 { 53 r.name="Lisa"; 54 r.sex="woman"; 55 } 56 x=(x+1)%2; //保证if和else交替执行 57 r.b=false; 58 } 59 } 60 } 61 } 62 } 63 //创建一个输出资源属性的线程 64 class Output implements Runnable 65 { 66 private Resourse r; 67 Output(Resourse r) 68 { 69 this.r=r; 70 } 71 public void run() 72 { 73 while(true) //保证while内的代码循环执行 74 { 75 synchronized(r) //锁是Resourse类对象,和上文是同一个锁,实现同步 76 { 77 while(r.b==false) 78 { 79 System.out.println(r.name+" "+r.sex); 80 r.b=true; 81 } 82 } 83 } 84 } 85 } 86 */ 87 //多线程通信方法二 88 /* 89 //创建一个共享资源,人 90 class Resourse 91 { 92 String name; 93 String sex; 94 boolean b=true; 95 } 96 //创建一个为资源赋值的线程 97 class Input implements Runnable 98 { 99 private Resourse r; 100 Input(Resourse r) 101 { 102 this.r=r; 103 } 104 public void run() 105 { 106 int x=0; 107 while(true) 108 { 109 synchronized(r) //锁是Resourse类对象 110 { 111 if(!r.b) //进行线程停止等待,如果r.b为真则执行if语句内的程序 112 try{r.wait();}catch(Exception e){} 113 if(x==0) 114 { 115 r.name="Joe"; 116 r.sex="man"; 117 } 118 else 119 { 120 r.name="Lisa"; 121 r.sex="woman"; 122 } 123 x=(x+1)%2; //保证if和else交替执行 124 r.b=false; 125 r.notify(); //线程的锁需要标识 126 } 127 } 128 } 129 } 130 //创建一个输出资源属性的线程 131 class Output implements Runnable 132 { 133 private Resourse r; 134 Output(Resourse r) 135 { 136 this.r=r; 137 } 138 public void run() 139 { 140 while(true) //保证while内的代码循环执行 141 { 142 synchronized(r) //锁是Resourse类对象,和上文是同一个锁,实现同步 143 { 144 if(r.b) //线程停止等待 145 try{r.wait();}catch(Exception e){} 146 System.out.println(r.name+" "+r.sex); 147 r.b=true; 148 r.notify(); 149 } 150 } 151 } 152 } 153 */ 154 //多线程通信代码优化 155 //创建一个共享资源,人 156 class Resourse 157 { 158 private String name; 159 private String sex; 160 boolean circle=true; 161 public synchronized void setNameSex(String name,String sex) 162 { 163 if(!this.circle) 164 try{wait();}catch(Exception e){} 165 this.name=name; 166 this.sex=sex; 167 circle=false; 168 notify(); 169 } 170 public synchronized void out() 171 { 172 if(this.circle) //线程停止等待 173 try{wait();}catch(Exception e){} 174 circle=true; 175 notify(); 176 System.out.println(name+" "+sex); 177 } 178 } 179 //创建一个为资源赋值的线程 180 class Input implements Runnable 181 { 182 private Resourse r; 183 Input(Resourse r) 184 { 185 this.r=r; 186 } 187 public void run() 188 { 189 int x=0; 190 while(true) 191 { 192 if(x==0) 193 r.setNameSex("Joe", "man"); 194 else 195 r.setNameSex("Lisa", "woman"); 196 x=(x+1)%2; //保证if和else交替执行 197 } 198 } 199 } 200 //创建一个输出资源属性的线程 201 class Output implements Runnable 202 { 203 private Resourse r; 204 Output(Resourse r) 205 { 206 this.r=r; 207 } 208 public void run() 209 { 210 while(true) //保证while内的代码循环执行 211 { 212 r.out(); 213 } 214 } 215 }
9、JDK1.5以上的版本提供了多线程的解决方案,它将同步synchronized替换成了lock操作,将Object中的wait,notify和notifyAll替换成了condition对象,该对象可以以lock锁来获取,condition对象的single可以实现本方唤醒对方的功能。
代码:线程间通信之两个生产者和两个消费者问题,生产者生产的商品全部由消费者消费,是一个平衡问题。
1 package pack; 2 import java.util.concurrent.locks.*; 3 //线程间的通信,两个生产者,两个消费者和一个同种共享商品资源,每个商品都有标号,由count计数。 4 public class ThreadCommunication 5 { 6 public static void main(String[] args) 7 { 8 Shop s=new Shop(); 9 Producer p=new Producer(s); //以构造函数初始化p对象 10 Consumer c=new Consumer(s); 11 Thread t1=new Thread(p,"生产者1"); //runnable子类对象作为参数传入Thread构造函数中,实例化t1线程 12 Thread t11=new Thread(p,"生产者2"); //两个生产者对象 13 Thread t2=new Thread(c,"消费者1"); //两个消费者对象 14 Thread t22=new Thread(c,"消费者2"); 15 t1.start(); //启动4个线程 16 t11.start(); 17 t2.start(); 18 t22.start(); 19 } 20 } 21 //定义商品资源 22 class Shop 23 { 24 private String name; //定义商品名字 25 private int count=1; //定义商品编号 26 private boolean flag=false; //定义标记,方便循环赋值 27 private final Lock lock=new ReentrantLock(); //引用接口Lock,实例化ReentrantLock类 28 private Condition condition1=lock.newCondition(); //调用Lock类的newCondition()方法,创建锁 29 private Condition condition2=lock.newCondition(); 30 public void setName(String name) throws InterruptedException //属性构造器,为类属性赋值 31 { 32 lock.lock(); 33 try 34 { 35 while(flag) 36 condition1.await(); //线程停止等待 37 this.name=name+"编号:"+count++; //打印出商品名和商品编号 38 System.out.println(Thread.currentThread().getName()+"---"+this.name);//打印生产者进程 39 flag=true; 40 condition2.signal(); //唤醒线程 41 } 42 finally 43 { 44 lock.unlock(); 45 } 46 } 47 public void out() throws InterruptedException 48 { 49 lock.lock(); 50 try 51 { 52 while(!flag) 53 condition2.await(); 54 System.out.println(Thread.currentThread().getName()+"---"+this.name);//打印消费者进程 55 flag=false; 56 condition1.signal(); 57 } 58 finally //关闭锁是必须执行的部分 59 { 60 lock.unlock(); 61 } 62 } 63 } 64 //定义生产者,生产者为Shop类对象赋值 65 class Producer implements Runnable 66 { 67 private Shop s=new Shop(); //实例化Shop类对象s 68 Producer(Shop s) //用Shop类对象作为参数传递给构造函数 69 { 70 this.s=s; 71 } 72 public void run() 73 { 74 while(true) 75 { 76 try 77 { 78 s.setName("商品"); 79 } 80 catch(InterruptedException e) 81 {} 82 } 83 } 84 } 85 //定义消费者 86 class Consumer implements Runnable 87 { 88 private Shop s=new Shop(); 89 Consumer(Shop s) 90 { 91 this.s=s; 92 } 93 public void run() 94 { 95 while(true) 96 { 97 try 98 { 99 s.out(); 100 } 101 catch(InterruptedException e) 102 {} 103 } 104 } 105 }
10、stop和suspend方法已经过时,让线程结束就是让run方法结束。开启多线程,run方法内的结构一般是循环结构,控制住循环,线程则结束。线程都进入冻结状态,线程就无法停止了,此时需要强制清楚冻结状态,进入运行状态,使用interrupt();方法。
11、所有的前台线程都结束后,后台线程才可以结束。主线程是前台线程。后台线程就是守护线程。
12、线程.join();方法时要求CPU的执行权。此函数的特点是:当A线程执行到了B线程的join方法时,A线程就会等待,直到执行完,A才会执行。join可以临时加入线程执行,抢占CPU执行资格。
13、线程组:谁开启了线程组(比如main),谁就是那个组的组名。所有的线程的优先级的默认值都是5。
14、多线程计数,计算运行时间。
1 package pack; 2 import java.util.concurrent.CountDownLatch; 3 public class Test 4 { 5 public static void main(String[] args) 6 { 7 long start=System.currentTimeMillis(); 8 final CountDownLatch l=new CountDownLatch(3); //使三个线程在完成操作之前一直等待 9 //匿名内部类可以实现一个线程,作为一个小技巧提高程序运行效率 10 new Thread() 11 { 12 public void run() 13 { 14 for(int i=0;i<30000;i++) 15 { 16 System.out.println(Thread.currentThread().getName()+"---"+i); 17 } 18 l.countDown(); 19 } 20 }.start(); 21 22 //另一个匿名内部类 23 Runnable r=new Runnable() 24 { 25 public void run() 26 { 27 for(int i=0;i<30000;i++) 28 { 29 System.out.println(Thread.currentThread().getName()+"---"+i); 30 } 31 l.countDown(); 32 } 33 }; 34 new Thread(r).start(); 35 36 //主线程的代码 37 38 for(int i=0;i<30000;i++) 39 { 40 System.out.println(Thread.currentThread().getName()+"---"+i); 41 } 42 l.countDown(); 43 44 try 45 { 46 l.await(); //当前线程(主线程)在倒计数至零之前一直在等待 47 } 48 catch(InterruptedException e) 49 { 50 e.toString(); 51 } 52 long end=System.currentTimeMillis(); 53 System.out.println("运行的时间是:"+(end-start)/1000.0+"秒"); 54 55 } 56 }
以上代码均来自于毕老师的指导。