JAVA多线程 & 同步关键词synchronized & ReadWriteLock读写文件

  在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限。

1 public class Actor extends Thread  {
2     public void run(){
3          //线程执行的操作
4         }
5 }   

  在实际开发中一个多线程的操作很少使用Thread类,而是通过Runnable接口完成。

1 public class Actress implements Runnable{
2 
3     @Override
4     public void run() {
5         //线程执行的操作
6         }
7 }    

  在主方法中调用这两种线程。

1     public static void main(String[] args) {
2         Thread actor=new Actor();
3         actor.setName("Mr.thread");  //Thread 线程
4         actor.start();
5         
6         Thread actressThread=new Thread(new Actress(),"Miss.Runnable");  //Runnable 线程
7         actressThread.start();
8     }

 

两种实现方式的区别和联系:

  在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:

    1、避免点继承的局限,一个类可以继承多个接口。

    2、适合于资源的共享

  以卖票程序为例,通过Thread类完成:

 1 package multithreading;
 2 
 3 public class MyThreadWithExtends extends Thread {
 4 
 5     private int tickets = 10;
 6 
 7     @Override
 8     public void run() {
 9 
10         for (int i = 0; i <= 100; i++) {
11             if(tickets>0){
12                 System.out.println(Thread.currentThread().getName()+"--卖出票:" + tickets--);
13             }
14         }
15     }
16     
17     
18     public static void main(String[] args) {
19         MyThreadWithExtends thread1 = new MyThreadWithExtends();
20         MyThreadWithExtends thread2 = new MyThreadWithExtends();
21         MyThreadWithExtends thread3 = new MyThreadWithExtends();
22 
23         thread1.start();
24         thread2.start();
25         thread3.start();
26         
27         //每个线程都独立,不共享资源,每个线程都卖出了10张票,总共卖出了30张。如果真卖票,就有问题了。
28     }
29 
30 }

运行结果:

  Thread-0--卖出票:10
  Thread-2--卖出票:10
  Thread-1--卖出票:10
  Thread-2--卖出票:9
  Thread-0--卖出票:9
  Thread-2--卖出票:8
  Thread-1--卖出票:9
  Thread-2--卖出票:7
  Thread-0--卖出票:8
  Thread-2--卖出票:6
  Thread-2--卖出票:5
  Thread-2--卖出票:4
  Thread-1--卖出票:8
  Thread-2--卖出票:3
  Thread-0--卖出票:7
  Thread-2--卖出票:2
  Thread-2--卖出票:1
  Thread-1--卖出票:7
  Thread-0--卖出票:6
  Thread-1--卖出票:6
  Thread-0--卖出票:5
  Thread-0--卖出票:4
  Thread-1--卖出票:5
  Thread-0--卖出票:3
  Thread-1--卖出票:4
  Thread-1--卖出票:3
  Thread-1--卖出票:2
  Thread-0--卖出票:2
  Thread-1--卖出票:1
  Thread-0--卖出票:1

 

  如果用Runnable就可以实现资源共享,下面看例子:

 1 package multithreading;
 2 
 3 public class MyThreadWithImplements implements Runnable {
 4 
 5     private int tickets = 10;
 6 
 7     @Override
 8     public void run() {
 9 
10         for (int i = 0; i <= 100; i++) {
11             if(tickets>0){
12                 System.out.println(Thread.currentThread().getName()+"--卖出票:" + tickets--);
13             }
14         }
15     }
16     
17     
18     public static void main(String[] args) {
19         MyThreadWithImplements myRunnable = new MyThreadWithImplements();
20         Thread thread1 = new Thread(myRunnable, "窗口一");
21         Thread thread2 = new Thread(myRunnable, "窗口二");
22         Thread thread3 = new Thread(myRunnable, "窗口三");
23 
24         thread1.start();
25         thread2.start();
26         thread3.start();
27     }
28 
29 }

运行结果:

  窗口二--卖出票:10
  窗口三--卖出票:9
  窗口一--卖出票:8
  窗口三--卖出票:6
  窗口三--卖出票:4
  窗口三--卖出票:3
  窗口三--卖出票:2
  窗口三--卖出票:1
  窗口二--卖出票:7
  窗口一--卖出票:5

每个线程共享了对象myRunnable的资源,卖出的总票数是对的,但是顺序是乱的,怎么办?

 

同步关键词synchronized

 

线程执行的时候,一个个执行不就有序了。即线程1在执行的时候,其他线程阻塞不要执行。

加synchronize。

 1 package multithreading.sync;
 2 
 3 public class MyThreadWithImplements implements Runnable {
 4 
 5     private int tickets = 10;
 6 
 7     @Override
 8     public synchronized void run() {
 9             //同步关键词synchronized
10         for (int i = 0; i <= 100; i++) {
11             if(tickets>0){
12                 System.out.println(Thread.currentThread().getName()+"--卖出票:" + tickets--);
13             }
14         }
15     }
16     
17     
18     public static void main(String[] args) {
19         
20         MyThreadWithImplements myRunnable = new MyThreadWithImplements();
21         Thread thread1 = new Thread(myRunnable, "窗口一");
22         Thread thread2 = new Thread(myRunnable, "窗口二");
23         Thread thread3 = new Thread(myRunnable, "窗口三");
24 
25         thread1.start();
26         thread2.start();
27         thread3.start();
28     }
29 
30 }

运行结果

  窗口一--卖出票:10
  窗口一--卖出票:9
  窗口一--卖出票:8
  窗口一--卖出票:7
  窗口一--卖出票:6
  窗口一--卖出票:5
  窗口一--卖出票:4
  窗口一--卖出票:3
  窗口一--卖出票:2
  窗口一--卖出票:1

 

缺陷

  1、如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,这多么影响程序执行效率。


  2、当有多个线程读写文件时,读写操作会发生冲突现象,写操作会发生冲突现象,但是读操作不会发生冲突现象。但是采用synchronized关键字来实现同步的话,就会导致一个问题:如果多个线程都只是进行读操作,当一个线程在进行读操作时,其他线程只能等待无法进行读操作。


  因此就需要一种机制来使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到。另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的。总的来说,也就是说Lock提供了比synchronized更多的功能。

ReadWriteLock读写文件

概述

ReadWriteLock是一个接口,在它里面只定义了两个方法:一个读的锁和一个写的锁。

读的锁:A线程获取了读的锁,那么B线程也可以获取读的锁。

写的锁:A线程获取了写的锁,那么B线程不能获取读也不能获取写的锁。

 1 public interface ReadWriteLock {  
 2     /** 
 3      * Returns the lock used for reading. 
 4      * 读的锁,A线程获取了读的锁,那么B线程也可以获取读的锁 
 5      * @return the lock used for reading. 
 6      */  
 7     Lock readLock();  
 8    
 9     /** 
10      * Returns the lock used for writing. 
11      * 写的锁,A线程获取了写的锁,那么B线程不能获取读也不能获取写的锁。 
12      * @return the lock used for writing. 
13      */  
14     Lock writeLock();  
15 } 

。。。未完待续

 

posted @ 2018-05-08 20:06  阿衰问问  阅读(1834)  评论(0编辑  收藏  举报