java 线程同步以及数据安全 synchronized 的使用

Day20线程安全问题

一、线程同步以及数据安全

1、概念:

多个线程同时执行,在任意时刻 都可能被其他的线程抢占cpu,经过互相抢占,最终的结果可能有重复或者丢失

2、线程同步

线程的同步有两种方式一种是通过synchronized (o) {}同步代码块还有一种是同步方法直接在方法中加上synchronized对方法进行修饰,在同一时刻,只能有一个线程来执行特定的代码

3、同步代码块:

synchronized(锁){  任意锁   互斥锁 

                            需要被同步的代码

}

锁的概念:

以上代码中的锁可以是任意对象,但必须是唯一的,又叫互斥锁,由于是多个线程共用一个,且每次只能给一个线程用,一个线程用完之后在由线程跟线程之间进行竞争,固又叫互斥锁。

4、同步方法:

使用同步方法格式如下:

public synchronized void method(){

         写需要被同步的代码

}

在非静态方法中同步方法的锁默认是this同步方法要想被执行,就需要被调用

同步静态方法:与同步非静态方法不同点就是锁不一样锁是资源类.class的Class对象

二、共享资源同步代码的操作

1、相同操作,共享资源:

         使用同步代码块: 在run方法中就可以直接使用锁this

         使用同步方式: 在资源类中创建同步方法在run方法中调用锁默认是 this

2、不同操作 共享资源

         使用同步代码块: 在不同的操作类的run方法中使用,锁是资源类对象

         使用同步方法: 在资源类中创建同步方法默认的锁是this也就是资源类对象

3、懒汉式的单例

         public static LazyInstance getInstance(){

                   if(instance==null){// 第一次检查 对象是否为空 ,为空 则去判断 锁,如果不为空  直接返回 (提高效率降低锁的对比此数)

                            synchronized(LazyInstatnce.class){

                                     if(instance==null){//第二次检查   确保不会创建多个实例,如果为空就创建  不为空则 返回

                                               instance = new LazyInstatnce();

                                     }

                            }

                   }

         }

 

 

 

三、死锁和守护进程

1、概念:

线程双方都持有者自己的锁 不放,还需要对象的锁,僵持 产生死锁

2、形成条件:

1)同步嵌套

2)锁不同

代码如下:(关键代码)

public class Test {

 

         public static void main(String[] args) {

                   GirlFriend friend = new GirlFriend();

                   BoyFriend friend2 = new BoyFriend();

                  

                   friend.start();

                   friend2.start();

         }

}

 

class GirlFriend extends Thread{

         @Override

         public void run() {

                   synchronized (Lock.a) {

                            System.out.println("女朋友拿到了筷子a");

                            synchronized (Lock.b) {

                                     System.out.println("女朋友拿着筷子b");

                            }

                   }

         }

        

        

}

 

class BoyFriend extends Thread{

         @Override

         public void run() {

                   try {

                            Thread.sleep(300);

                   } catch (InterruptedException e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                   }

                   synchronized (Lock.b) {

                            System.out.println("男朋友拿到了筷子b");

                            synchronized (Lock.a) {

                                     System.out.println("男朋友拿到了筷子a");

                            }

                   }

         }

}

 

class Lock{

         static Object a = new Object();

         static Object b = new Object();

}

 

3、守护线程:

子线程设置成为守护线程, 当主线程 执行完了,子线程就结束执行

线程对象.setDaemon(true)默认为false

设置守护线程的方法要写在 start前面

代码如下(关键代码):

public class Test2 {

 

         public static void main(String[] args) {

                   MyThread2 thread2 = new MyThread2();

                   thread2.setDaemon(true);// true 此线程是守护线程

                   thread2.start();

                   for (int i = 0; i < 10; i++) {

                            System.out.println("主线程执行"+i);

                   }

         }

}

 

class MyThread2 extends Thread{

         @Override

         public void run() {

                   for (int i = 0; i < 10000; i++) {

                            System.out.println("子线程执行了"+i);

                   }

         }

}

 

四、线程间通信:

1、线程实现有序执行

各个方法介绍:

wait()挂起当前线程, 让当前线程进入到阻塞状态

notify()随机唤醒一个因为调用wait进入阻塞状态的线程

notifyAll()将所有的因为wait进入到阻塞状态的线程全部唤醒

都是来资源Object 类 ,在任何类中都可以调用

必须在同步方法或者同步代码块中调用  否则 IllegalMonitorStateException

2、wait()和sleep()的区别

相同点:

都可以使线程进入到阻塞状态

不同点:

1 sleep() 设定时间到了,可以自己进入到可执行状态

wait() 必须要通过notify唤醒 才能进入到 可执行状态

2 sleep 可以释放 cpu资源,不能释放锁资源

wait() 释放了cpu  也释放了锁

代码实现如下:

package com.LiLinXiong.work2;

 

public class TestPrintABC123 {

    public static void main(String[] args) {

      

       //第二种方法

       Object o = new Object();

       Printabc printabc = new Printabc(o);

       Print123 print123 = new Print123(o);

      

       Thread thread = new Thread(print123);

       Thread thread2 = new Thread(printabc);

       thread.start();

       thread2.start();

             

    }

}

 

 

class Printabc implements Runnable{

    Object o;

    public Printabc(Object o) {

       this.o = o;

    }

    @Override

    public void run(){

       synchronized (o) {

           for (int i = 65; i < 91; i++) {

              System.out.print((char)i);

              if(i == 90){

                  o.notify();

                  break;

              }

              try {

                  o.notify();

                  o.wait();

              } catch (InterruptedException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

              }

           }

       }

    }

}

 

class Print123 implements Runnable{

    Object o;

   

    public Print123(Object o) {

       this.o = o;

    }

    @Override

    public void run() {

       synchronized (o) {

           for (int i = 1; i <= 52; i++) {

              System.out.print(i);

              if(i == 52){

                  o.notify();

                  break;

              }

              if(i%2==0){

                  o.notify();

                  try {

                     o.wait();

                  } catch (InterruptedException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

                  }

              }

           }

       }

    }

}

 

                  

 

posted @ 2017-04-24 20:42  java李  阅读(186)  评论(0编辑  收藏  举报