Java提高——多线程(三)同步、锁

线程同步

线程的同步是为了防止多个线程访问同一个数据对象时,对数据造成破坏。

同步的方法就是使用synchronized关键字。

每个对象有且仅有一个同步锁,意味着同步锁依赖于对象而存在。每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法时,自动获得与当前执行的代码类的当前实例(this)有关的锁。当程序运行到synchronized方法时,就获得了该对象的同步锁。不同线程对同步锁是互斥的

synchronized(obj){、、、、、}——>获得了obj对象的同步锁。

synchronized可以修饰方法和代码块,但是不能修饰构造器、成员变量等。

synchronized的规则:

—>当一个线程访问一个synchronized方法或代码块时,其他线程对该对象访问将被阻塞。

—>当一个线程访问一个synchronized方法或代码块时,其他线程可以访问该对象的非同步代码块

—>当一个线程访问一个synchronized方法或代码块时,其他线程对该对象的其他synchronized方法或代码块将被阻塞。

1、

public class SynchronizedTest {
    public static void main(String[] args) {
        Runnable demo = new demo1();

        Thread t1 = new Thread(demo,"t1");
        Thread t2 = new Thread(demo,"t2");
        t1.start();
        t2.start();
    }
    static class demo1 implements Runnable{
        @Override
        public void run(){
            synchronized (this){
                for (int i = 0; i < 10; i++) {
                    System.out.print(Thread.currentThread().getName()+"-"+i+" ");
                }
            }
        }
    }
}

2、

public class SynchronizedTest {
    public static void main(String[] args) {
        final demo1 demo = new demo1();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.ru();
            }
        }, "t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.go();
            }
        }, "t2");
        t1.start();
        t2.start();
    }
}
 class demo1{
    public void ru(){
        synchronized (this){
            for (int i = 0; i < 10; i++) {
                System.out.print(Thread.currentThread().getName()+"-"+i+" ");
            }
        }
    }
    public void go(){
        System.out.println("非同步方法");
    }
}

3、

public class SynchronizedTest {
    public static void main(String[] args) {
        final demo1 demo = new demo1();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.ru();
            }
        }, "t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                demo.go();
            }
        }, "t2");
        t1.start();
        t2.start();
    }
}
 class demo1{
    public void ru(){
        synchronized (this){
            for (int i = 0; i < 10; i++) {
                System.out.print(Thread.currentThread().getName()+"-"+i+" ");
            }
        }
    }
    public void go(){
        synchronized (this) {
            System.out.println("非");
            for (int i = 0; i < 10; i++) {
                System.out.print(Thread.currentThread().getName()+"-"+i+" ");
            }
        }
    }
}
同步锁(Lock)

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

实现线程控制中比较常用的是ReentrantLock(可重入锁),使用该锁可以显示的加锁、释放锁

class ruo{
    //获取锁对象
    private final ReentrantLock loc = new ReentrantLock();
    //......
    public void re(){
        //加锁
        loc.lock();
        try{
            //需要保证线程安全的代码
            //.....
        }finally {
            //释放锁
            loc.unlock();
        }
    }
}

使用Lock与同步方法有点类似,只是Lock是显示的使用Lock对象作为同步锁,而使用同步方法是系统隐式的使用当前对象作为同步监视器。

ReentantLock具有可重入性,就是一个线程可以对已被加锁的ReentrantLock锁再次加锁。

死锁

当两个线程相互等待对方释放同步监视器的时候就会发生死锁。一旦发生死锁,程序不会发生任何异常也不会有任何提示,只是所有线程被阻塞,无法继续。

class A{
    public synchronized void foo(B b){
        System.out.println("foo方法");
        b.last();
    }
    public synchronized void last(){
        System.out.println("a.last");
    }
}
class B{
    public synchronized void bar(A a){
        System.out.println("bar方法");
        a.last();
    }
    public synchronized void last(){
        System.out.println("b.last");
    }
}
public class DeadLock implements Runnable{
    A a = new A();
    B b = new B();
    public void init(){
        Thread.currentThread().setName("主线程");
        a.foo(b);
    }
    @Override
    public void run() {
        Thread.currentThread().setName("副线程");
        b.bar(a);
    }
    public static void main(String[] args) {
        DeadLock deadLock = new DeadLock();
        //以deadLock为target启动新的线程
        new Thread(deadLock).start();
        //调用init()方法
        deadLock.init();
    }
}

程序发生死锁,没提醒,无异常




posted @ 2018-05-07 16:35  惶者  阅读(179)  评论(0编辑  收藏  举报