关于java线程的一些东西

一、先简单描叙一下创建线程的方式通过继承Thread:

(1)定义一个类继承Thread类

(2)覆盖Thread类中的run方法

(3)直接创建Thread的子类对象线程

(4)调用start方法开启线程并调用线程的任务run方法执行

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public class ThreadDemo extends Thread {  
  2.       
  3.     private String name;  
  4.     public ThreadDemo(String name){  
  5.         this.name = name;  
  6.     }  
  7.       
  8.     public void run(){  
  9.         for(int i = 0; i < 9; i++){  
  10.             System.out.println(name+"..........i="+i);  
  11.         }  
  12.     }  
  13.       
  14.     public static void main(String[] args) {  
  15.         ThreadDemo demo = new ThreadDemo("李四");  
  16.         ThreadDemo demo1 = new ThreadDemo("张三");  
  17.         demo.start();  
  18.         demo1.start();  
  19.     }  
  20. }  

二、run方法和start方法的区别

1.start()方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码:
通过调用Thread类的start()方法来启动一个线程, 
这时此线程是处于就绪状态, 
并没有运行。 
然后通过此Thread类调用方法run()来完成其运行操作的, 
这里方法run()称为线程体, 
它包含了要执行的这个线程的内容, 
Run方法运行结束, 
此线程终止, 
而CPU再运行其它线程, 
 
2.run()方法当作普通方法的方式调用,程序还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码:
 
而如果直接用Run方法, 
这只是调用一个方法而已, 
程序中依然只有主线程--这一个线程, 
其程序执行路径还是只有一条, 
这样就没有达到写线程的目的。 
 
举例说明一下:
记住:线程就是为了更好地利用CPU, 
提高程序运行速率的! 


java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。

描述实现Runnable接口

(一)创建一个类,实现Runnable接口

(二)复写Runnable里面的run方法

(三)实例化这个类,调用start方法,此时线程开启,就执行该线程的run方法

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. class MyThread implements Runnable{  
  2.    
  3.     private int ticket = 5;  //5张票  
  4.    
  5.     public void run() {  
  6.         for (int i=0; i<=20; i++) {  
  7.             if (this.ticket > 0) {  
  8.                 System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--);  
  9.             }  
  10.         }  
  11.     }  
  12. }  
  13.   
  14. public class lzwCode {  
  15.        
  16.     public static void main(String [] args) {  
  17.         MyThread my = new MyThread();  
  18.         new Thread(my, "1号窗口").start();  
  19.         new Thread(my, "2号窗口").start();  
  20.         new Thread(my, "3号窗口").start();  
  21.     }  
  22. }  

实现Runnable接口的好处如下:

1.避免了java里面的单继承问题

2.适合多个相同的程序代码的线程去处理同一个资源

3.增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

一、产生线程安全的原因

(1)多个线程在操作共享数据

(2)操作共享数据的线程代码有多条

结论:当一个线程在执行操作共享数据的多条代码过程中,其他线程参与运算,就会导致线程安全问题的产生。

二、解决方案:同步锁,同步锁分为两种如下:

(1)同步锁代码块

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. Synchronized(对象){  
  2.     //code;  
  3. }  


(2)同歩锁函数

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public synchronized void show(){  
  2.     //code;  
  3. }  

 同步锁函数和同步代码块的区别:

①同步函数的锁是固定的this;

②同步代码块的锁是任意的对象;

③静态的同步函数使用的锁是该函数所属字节码文件对象,可以用getClass()方法获取,也可以用当前类名.class获取;

(3)使用同歩锁的前提:必须有多个线程并同时使用同一个锁;

三、死锁原因

(1)同步锁嵌套

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. synchronized(MyLocked.locka){  
  2.     System.out.println(Thread.currentThread().getName()+" if locka....");  
  3.     synchronized(MyLocked.lockb){  
  4.         System.out.println(Thread.currentThread().getName()+" if lockb....");  
  5.     }  
  6. }  


(2)线程间的通讯,多个线程在处理同一个资源,但任务却不同

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. //资源  
  2. class Resource  
  3. {  
  4.     String name;  
  5.     String sex;  
  6. }  
  7.   
  8.   
  9. //输入  
  10. class Input implements Runnable  
  11. {  
  12.     Resource r ;  
  13. //  Object obj = new Object();  
  14.     Input(Resource r)  
  15.     {  
  16.         this.r = r;  
  17.     }  
  18.     public void run()  
  19.     {  
  20.         int x = 0;  
  21.         while(true)  
  22.         {  
  23.             synchronized(r)  
  24.             {  
  25.                 if(x==0)  
  26.                 {  
  27.                     r.name = "mike";  
  28.                     r.sex = "nan";  
  29.                 }  
  30.                 else  
  31.                 {  
  32.                     r.name = "丽丽";  
  33.                     r.sex = "女女女女女女";  
  34.                 }  
  35.             }  
  36.             x = (x+1)%2;  
  37.   
  38.         }  
  39.     }  
  40. }  
  41. //输出  
  42. class Output implements Runnable  
  43. {  
  44.   
  45.     Resource r;  
  46. //  Object obj = new Object();  
  47.     Output(Resource r)  
  48.     {  
  49.         this.r = r;  
  50.     }  
  51.   
  52.     public void run()  
  53.     {  
  54.         while(true)  
  55.         {  
  56.             synchronized(r)  
  57.             {  
  58.                 System.out.println(r.name+"....."+r.sex);  
  59.             }  
  60.         }  
  61.     }  
  62. }  
  63.   
  64.   
  65.   
  66. class  ResourceDemo  
  67. {  
  68.     public static void main(String[] args)   
  69.     {  
  70.         //创建资源。  
  71.         Resource r = new Resource();  
  72.         //创建任务。  
  73.         Input in = new Input(r);  
  74.         Output out = new Output(r);  
  75.         //创建线程,执行路径。  
  76.         Thread t1 = new Thread(in);  
  77.         Thread t2 = new Thread(out);  
  78.         //开启线程  
  79.         t1.start();  
  80.         t2.start();  
  81.     }  
  82. }  


四、等待/唤醒机制

(1)wait();让线程处于冻结状态,被wait的线程会被存储到线程池中;

(2)notify();唤醒线程池中一个线程(任意);

(3)notifyAll();唤醒线程池中的所有线程;

总结:这些方法都必须能定义在同步锁中,因为这些方法是用于操作线程状态的方法,必须能要明确到底操作的是哪个锁上的线程




为什么操作线程的方法wait notify notifyAll定义在了Object类中? 
因为这些方法是监视器的方法。监视器其实就是锁。锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。


五、示例如下:


资源类:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">package com.edu.csu.syn;  
  2.   
  3. public class Resource {  
  4.       
  5.     private String name;  
  6.     private String sex;  
  7.     private boolean flag = false;  
  8.       
  9.     public synchronized void set(String name,String sex){  
  10.         if(flag)  
  11.             try {  
  12.                 this.wait();  
  13.             } catch (InterruptedException e) {  
  14.                 e.printStackTrace();  
  15.             }  
  16.             this.name = name;  
  17.             this.sex = sex;  
  18.             flag = true;  
  19.             this.notify();  
  20.           
  21.     }  
  22.       
  23.     public synchronized void out(){  
  24.         if(!flag)  
  25.             try {  
  26.                 this.wait();  
  27.             } catch (InterruptedException e) {  
  28.                 e.printStackTrace();  
  29.             }  
  30.         System.out.println(name+"......"+sex);  
  31.         flag = false;  
  32.         this.notify();  
  33.     }  
  34. }  
  35. </span>  

输入类:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">package com.edu.csu.syn;  
  2.   
  3. public class Input implements Runnable {  
  4.       
  5.     private Resource r;  
  6.       
  7.     public Input(Resource r){  
  8.         this.r = r;  
  9.     }  
  10.   
  11.     @Override  
  12.     public void run() {  
  13.         int x = 0;  
  14.         while(true){  
  15.             if (x == 0) {  
  16.                 r.set("mike""nan");  
  17.             } else {  
  18.                 r.set("丽丽""女女女女");  
  19.             }  
  20.   
  21.             x = (x + 1) % 2;  
  22.         }  
  23.     }  
  24.   
  25. }</span>  

输出类:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">package com.edu.csu.syn;  
  2.   
  3. public class Output implements Runnable {  
  4.       
  5.     private Resource r;  
  6.       
  7.     public Output(Resource r){  
  8.         this.r = r;  
  9.     }  
  10.     @Override  
  11.     public void run() {  
  12.         while(true){  
  13.             r.out();  
  14.         }  
  15.     }  
  16.   
  17. }</span>  

测试类:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:14px;">package com.edu.csu.syn;  
  2.   
  3. public class Test {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public static void main(String[] args) {  
  9.         //创建资源  
  10.         Resource r = new Resource();  
  11.         //创建任务  
  12.         Input i = new Input(r);  
  13.         Output o = new Output(r);  
  14.         //创建线程,执行任务  
  15.         Thread t = new Thread(i);  
  16.         Thread t1 = new Thread(o);  
  17.         //开启线程  
  18.         t.start();  
  19.         t1.start();  
  20.     }  
  21.   
  22. }  
  23. </span>  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值