Java培训课程之线程的同步

  • 问题的提出
    • 多个线程执行的不确定性引起执行结果的不稳定
    • 多个线程对账本的共享,会造成操作的不完整性,会破坏数据。

Java培训课程

1例  题

模拟火车站售票程序,开启三个窗口售票。

class Ticket implements Runnable {

       private int tick = 100;

 

       public void run(){

              while (true) {

                     if (tick > 0) {

                            System.out.println(Thread.currentThread().getName() + “售出车票,tick号为:” + tick–);

                     } else

                            break;

              }

  }

}

 

class TicketDemo {

       public static void main(String[] args) {

 

              Ticket t = new Ticket();

 

              Thread t1 = new Thread(t);

              Thread t2 = new Thread(t);

              Thread t3 = new Thread(t);

              t1.setName(“t1窗口”);

              t2.setName(“t2窗口”);

              t3.setName(“t3窗口”);

              t1.start();

              t2.start();

              t3.start();

       }

}

java培训课程

java培训课程

private int tick = 100;

 

       public void run() {

              while (true) {

                     if (tick > 0) {

                            try {

                                   Thread.sleep(10);

                            } catch (InterruptedException e) {

                                   e.printStackTrace();

                            }

                            System.out.println(Thread.currentThread().getName() + “售出车票,tick号为:” + tick–);

                     }

              }

       }

 

  • 多线程出现了安全问题
  • 问题的原因:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。

  • 解决办法

对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。

2 Synchronized的使用方法

  • Java对于多线程的安全问题提供了专业的解决方式: 同步代码块

 

1)synchronized (对象){

          // 需要被同步的代码;

       }

  • synchronized还可以放在方法声明中,表示整个方法

      为同步方法。

例如:

      public synchronized void show (String name){

            ….

      }

java培训课程

3 同步锁(Lock)

从Java 5开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。

Lock是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。

在实现线程安全的控制中,比较常用的是ReentrantLock(可重入锁),可以显式加锁、释放锁。

 

class A {

    private final ReentrantLock lock = new ReenTrantLock();

 

    public void m() {

        lock.lock();

        try {

            // 保证线程安全的代码;

        } finally {

            lock.unlock();

        }

    }

}

 

 

4 互斥锁

  • 在Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
    • 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
    • 关键字synchronized 来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。
    • 同步的局限性:导致程序的执行效率要降低
    • 同步方法(非静态的)的锁为this。

             同步方法(静态的)的锁为当前类本身。

class Singleton {

    private static Singleton instance = null;

 

    private Singleton() {

    }

 

    public static Singleton getInstance() {

        if (instance == null) {

            synchronized (Singleton.class) {

                if (instance == null) {

                   instance = new Singleton();

                }

            }

        }

        return instance;

    }

}

 

public class TestSingleton {

    public static void main(String[] args) {

        Singleton s1 = Singleton.getInstance();

        Singleton s2 = Singleton.getInstance();

        System.out.println(s1 == s2);

    }

}

5 小结:释放锁的操作

  • 当前线程的同步方法、同步代码块执行结束
  • 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
  • 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
  • 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。

7 线程的死锁问题

  • 死锁
    • 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
  • 解决方法
    • 专门的算法、原则
    • 尽量减少同步资源的定义

 

 

public class TestDeadLock {

    public static void main(String[] args) {

        final StringBuffer s1 = new StringBuffer();

        final StringBuffer s2 = new StringBuffer();

        new Thread() {

            public void run() {

                synchronized (s1) {

                   s2.append(“A”);

                   synchronized (s2) {

                       s2.append(“B”);

                       System.out.print(s1);

                       System.out.print(s2);

                   }

                }

            }

        }.start();

        new Thread() {

            public void run() {

                synchronized (s2) {

                   s2.append(“C”);

                   synchronized (s1) {

                       s1.append(“D”);

                       System.out.print(s2);

                       System.out.print(s1);

                   }

                }

            }

        }.start();

    }

}


上一篇:
下一篇: