zoukankan      html  css  js  c++  java
  • 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 } 

    。。。未完待续

  • 相关阅读:
    assert的使用
    网络性能测试工具iperf的注意事项
    sskykeygen + sshcopyid避免ssh/scp每次输入密码
    遗留系统维护的思考
    IList(T)转换DataSet
    可扩展性(Extensibility): 构建灵活系统的思考
    页面加一个"数据正在载入,请等待... Loading, please wait..."的提示
    优化JavaScript
    创业与老子的顺其自然
    实用正则表达式匹配和替换
  • 原文地址:https://www.cnblogs.com/superslow/p/9010639.html
Copyright © 2011-2022 走看看