线程同步

6 篇文章 0 订阅

线程同步-可见性(非线程安全)

    (1)在并发线程中存在的线程安全问题,主要原因有

               [1]存在共享数据

               [2]多线程共同操作共享数据

    (2)volatile关键词---可见性(Visibility)

               [1] 功能:volatile关键字的作用很简单,就是一个线程在对主内存的某一份数据进行更改时,更改之后会立刻刷新主内存,并且会强制让缓存了该变量的线程中的数据清空,必须从主内存重新读取最新数据,这样一来就保证了可见性

               [2] 案例分析(注意volative关键字的作用,可以尝试将该关键词删除后进行运行)

package com.experiment_2_Thread.four;

public class TestVo  extends Thread{
	//stop相当于是一个环境变量
	//我们加入了一个volatile关键词,实现了刷新主内存的作用
	public volatile static boolean stop=false;
	@Override
	public void run() {
		  System.out.println("我开始了");
		  while (!stop) {
					
		}
		  System.out.println("我结束了");
	}

	//我们将sleep可能产生的异常进行抛出
	public static void main(String[] args) throws InterruptedException {
	  	TestVo testVo=new TestVo();
	  	testVo.start();
	  	//当前线程睡眠2s
	  	Thread.sleep(2000);
	  	stop=true;
	}
}

线程同步-原子性

    (1)介绍:

             [1]进入区(申请资源)------ 资源被占用,暂时不能访问,进入阻塞等待队列

             [2]临界区 -----只能有一个线程

             [3]退出去(释放资源)

    (2)Synchronized关键字

             [1]概述:java中每一个对象都可以有锁,这是Synchronized实现同步的基础

             [2]三种应用方式:

                       {1}普通同步方法(实例方法),锁是当前实例对象,进入同步代码前要获得当前实例的锁

                       {2}静态同步方法,锁是当前类的class对象,进入同步代码前要获得当前类对象的锁

                       {3}同步方法块,锁是括号里面的对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁

             [3]案例分析

 

{普通同步方法}

  {T1线程}

package com.experiment_2_Thread.four;

public class T1 implements Runnable {
    synchronized public void f1() {
        System.out.println(Thread.currentThread().getName()+"开始了");
        try {
            //让线程进行休眠2s
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"结束了");
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        f1();
    }

}

{Testsy}

package com.Test_P;

public class Testsy {
	public static void main(String[] args) {
		T1 t=new T1();
		Thread t1 = new Thread(t,"测试1");
		Thread t2 = new Thread(t,"测试2");
		t1.start();
		t2.start();
	}
}

运行结果:线程1和线程2依次进行运行,线程1运行结束后才开始运行线程2

 

{静态同步方法}

{T1线程}

package com.Test_P;

public class T1 implements Runnable {
	synchronized static public void f1() {
		System.out.println(Thread.currentThread().getName()+"开始了");
		try {
			//让线程进行休眠2s
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"结束了");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		f1();
	}

}

{Testsy}

package com.Test_P;

public class Testsy {
	public static void main(String[] args) {
		T1 t=new T1();
		T1 tt=new T1();
		Thread t1 = new Thread(t,"测试1");
		Thread t2 = new Thread(t,"测试2");
		Thread t3 = new Thread(tt,"测试3");
		t1.start();
		t2.start();
		t3.start();
	}
}

静态同步方法才让线程1,线程2,线程3依次执行,否则由于t3和t1,t2的对象不同会导致交错运行的结果

这个静态方法锁相当于是给类上了一个锁,只要是调用这个类的就必须要有锁

 

{同步方法块}

{不需要同步的System.out.println("测试")我们就没有放到同步语句块中}

{最上面的那个Object object = new Object(); 如果没有static就相当于普通同步方法}

package com.experiment_2_Thread.four;

public class T1 implements Runnable {
	//Object object=new Object();
	static Object object=new Object();
	public void f1() {
		System.out.println("测试");
		synchronized(object) 
		{
  			System.out.println(Thread.currentThread().getName()+"开始了");
			try {
				//让线程进行休眠2s
				Thread.sleep(2000);
			} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			}
  			System.out.println(Thread.currentThread().getName()+"结束了");
		}
	
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		 f1();
	}

}

{Testsy}

package com.experiment_2_Thread.four;

public class Testsy {
    public static void main(String[] args) {
	    T1 t=new T1();
	    T1 tt=new T1();
	    Thread t1=new Thread(t,"测试1");
	    Thread t2=new Thread(t,"测试2");
	    Thread t3=new Thread(tt,"测试3");
	    t1.start();
	    t2.start();
   	    t3.start();
    }
}

    (3)sychronized的缺点

             [1]效率低

             [2]锁的释放情况少,只在程序正常执行完成和抛出异常时释放锁

             [3]试图获得锁是不能设置超时的

             [4]不能中断一个正在试图获得锁的线程

             [5]无法知道是否成功获得到锁

Lock接口与ReentrantLock接口

    (1)与synchronized关键字相同的地方:他们实现的功能是一样的

    (2)与synchronized关键字不同的地方:

             [1]Lock有比synchronized更精确的线程语义和更好的性能

             [2]synchronized会自动释放锁,Lock要求程序员手工释放,且必须在finally语句中

    (3)使用锁进行同步机制(实例)

  {T2线程}

package com.experiment_2_Thread.four;

import java.util.concurrent.locks.ReentrantLock;

public class T2 implements Runnable {
    ReentrantLock r=new ReentrantLock();
    public void f1() {
        r.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "开始了");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();

            }
            System.out.println(Thread.currentThread().getName() + "结束了");
        }
        //因为还锁只能在finally中进行所以必须要加try语句块
        finally {
            r.unlock();
        }
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        f1();
    }
}

  {TestLock}

package com.experiment_2_Thread.four;

public class TestLock {
    public static void main(String[] args) {
        T2 t2=new T2();
        Thread thread1=new Thread(t2,"测试1");
        thread1.start();
        Thread thread2=new Thread(t2,"测试2");
        thread2.start();
    }
}

 

wait()和notify()

    (1)wait():导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法

    (2)notify():唤醒正在等待的对象监视器的单个线程

    (3)notifyAll():唤醒正在等待的对象监视器的所有线程

    (4)实例分析

package com.experiment_2_Thread.four;

public class TestWait {
    static Object object = new Object();
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            public void run(){
                synchronized (object) {
                    System.out.println(Thread.currentThread().getName() + "开始了");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "结束了");
                }
            }
        });
        Thread thread1 = new Thread(new Runnable() {
            public void run(){
                synchronized (object) {
                    System.out.println(Thread.currentThread().getName() + "开始了");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "结束了");
                    object.notify();
                }
            }
        });
        thread.start();
        thread1.start();
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值