Java学习之同步代码块

多线程的安全问题:

    当多个线程访问共享数据时,可能会出现线程安全问题。

产生问题的原因:

    1.线程任务中有处理到共享的数据;

    2.线程任务中有多条对共享数据的操作。

    一个线程在操作共享数据的过程中,其他线程参与了运算,造成了数据的错误。


如何解决多线程的安全问题:

    只要保证多条操作共享数据的代码在某一时间段,被一条线程所执行,在期间不允许其他线程参与运算。


如何保证?

    1.使用同步代码块

        synchronized(锁){

                需要被同步的代码

        }    

注意:锁可以是任意对象,锁是唯一的。

同步在目前情况下保证了一次只能有一个线程在执行,其他的线程进不来。

同步代码块规则:

    当线程进入同步代码块的时候,先看一下有没有锁,如果有锁,就进入同步代码块中执行代码。进去的同时会获取这把锁,当代码执行完毕,出同步代码块时,将这把锁释放。如果没锁,线程在同步代码块前等待,有锁才进入。


好处:解决了多线程的安全问题。

弊端:降低了效率。

    

    2.同步方法(作用和同步代码块相同)

    也使用synchronized关键字,关键字声明在方法上。

public synchronized void run(){
     // 要同步的代码块
} 

    同步方法中是如何实现同步的?锁是什么?

        同步方法的同步实现方式和同步代码块一样,也是有锁的。同步方法的锁是this(本类的对象)。


    3.静态方法(和上面两种方法作用相同)

        静态方法同样有锁,不过和成员方法不同,由于静态方法加载的时候还没有对象,所以静态方法的锁用的是该类的字节码文件对象:类名.class。

    

Lock接口

    JDK1.5后出现。

    他比synchronized有更多的操作。

    lock();获取锁

    unlock();释放锁

    为了保证锁一定会被释放,可以使用finally。

    使用格式: 

try {
    // 操作共享数据的代码
} finally {
    // 释放锁
}


线程的死锁

    前提:

    1.必须要有同步锁的嵌套

synchronized(){
	synchronized(){

	}
}

    2.锁对象要唯一(两把锁都要保证唯一)

public class Test {
	public static void main(String[] args) {
		DeadLock deadLock = new DeadLock();
		Thread t1 = new Thread(deadLock);
		Thread t2 = new Thread(deadLock);
		t1.start();
		t2.start();
	}
}

// 实现Runnable接口
class DeadLock implements Runnable{
	// 标记,控制线程进程进入不同方法
	private boolean flag = false;
	@Override
	public void run() {
		// 防止线程正常运行,多试几次,直到出现死锁
		while(true) {
			if (!flag) {
				synchronized(LockA.LOCK_A) {
					System.out.println("我是if的A锁");
					synchronized (LockB.LOCK_B) {
						System.out.println("我是if的B锁");
					}
				}
				
			} else {
				synchronized(LockB.LOCK_B) {
					System.out.println("我是else的B锁");
					synchronized (LockA.LOCK_A) {
						System.out.println("我是else的A锁");
					}
				}
				
			}
			flag = !flag;
		}
	}
	
}

// 继承ReentrantLock类,定义静态常量锁
class LockA extends ReentrantLock {
	private LockA() {
	}
	public static final LockA LOCK_A = new LockA();
}

class LockB extends ReentrantLock {
	private LockB() {
	}
	public static final LockB LOCK_B = new LockB();
}


线程的停止:

    stop()方法    已经过时,不推荐使用。

    interrupt()方法    中断线程

        interrupt方法的作用:

            1.调用interrupt方法时,线程中有wait(),sleep()等方法,这时会抛出一个InterruptException异常,并且清楚中断。

       2.调用interrupt方法时,线程中没有上述方法,这时会设置(改变)中断状态的值(true---false)。

public class Test {
	public static void main(String[] args) throws InterruptedException {
		TestRunnable runnable = new TestRunnable();
		Thread t1 = new Thread(runnable);
		t1.start();
		t1.interrupt();
	}
}

class TestRunnable implements Runnable {

	@Override
	public void run() {              
		while (!Thread.interrupted()) {
			System.out.println("我是子线程" + ".......run");
		}
	}
	
}

    标记法

    声明一个标识,用来停止线程

public class Test {
	public static void main(String[] args) throws InterruptedException {
		TestRunnable runnable = new TestRunnable();
		Thread t1 = new Thread(runnable);
		t1.start();
		Thread.currentThread().sleep(3000);
		runnable.flag = true;
	}
}

class TestRunnable implements Runnable {
	// 声明一个标记,用来控制线程
	public boolean flag = false;
	@Override
	public void run() {
		while (!flag) {
			System.out.println("我是子线程" + ".......run");
		}
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值