Java 线程的数据共享


Java 线程共享数据的常用方法是给多个线程传递同一个对象,由这个对象通过 synchronized 关键字同步共享数据的访问,让数据在同一时间只有一个线程能操作它。

除了使用  synchronized 关键字外,还可以使用显式锁或原子变量来实现数据访问的同步。本文只讨论 synchronized 关键字的实现。

1、使用 Runnable 对象

实例化一个自定义 Runnable 对象,然后用这个 Runnable 对象启动多个线程:

public class TestThread {
    public static void main(String[] args) {
        SharedRunnable runnable = new SharedRunnable();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
}

class SharedRunnable implements Runnable{
    private int ticket = 10;
    public void run() {
        while(ticket > 0){
            ticket--;
            System.out.println("当前票数为:"+ticket);
        }
    }
}

2、使用普通对象

使用普通对象的好处是,可以在不同线程里执行不同的方法。

public class TestThread {
    public static void main(String[] args) {
        final SharedData sharedData = new SharedData();
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {
                public void run() {
                    sharedData.add();
                }
            }).start();

            new Thread(new Runnable() {
                public void run() {
                    sharedData.dec();
                }
            }).start();
        }
    }
}

class SharedData {
    private int ticket = 0;

    public synchronized void add() {
        ticket++;
        System.out.println("线程" + Thread.currentThread().getName() + " ticket 为:" + ticket);
    }

    public synchronized void dec() {
        ticket--;
        System.out.println("线程" + Thread.currentThread().getName() + " ticket 为:" + ticket);
    }
}

3、使用单例

单例的方法更灵活,因为它不用关心线程的启动。

比如 Play 的 Job 中是没办法在创建线程的时候传入对象的,因为线程是系统自动创建的,开发者无法介入。

public class TestThread {
    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {
                public void run() {
                    SharedData.instance().add();
                }
            }).start();

            new Thread(new Runnable() {
                public void run() {
                    SharedData.instance().dec();
                }
            }).start();
        }
    }
}

class SharedData {
    private static SharedData sharedData;
    private int ticket = 0;

    private SharedData() {
    }

    public static SharedData instance() {
        if (sharedData == null) {
            sharedData = new SharedData();
        }
        return sharedData;
    }

    public synchronized void add() {
        ticket++;
        System.out.println("线程" + Thread.currentThread().getName() + " ticket 为:" + ticket);
    }

    public synchronized void dec() {
        ticket--;
        System.out.println("线程" + Thread.currentThread().getName() + " ticket 为:" + ticket);
    }
}

4、静态方法

静态方法上也可以使用 synchronized,它同步对象是 ClassName.class,比如 TestThread.class。

public class TestThread {
    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {
                public void run() {
                    while (true) {
                        if (!dec()) return;
                    }
                }
            }).start();

            new Thread(new Runnable() {
                public void run() {
                    while (true) {
                        if (!dec()) return;
                    }
                }
            }).start();
        }
    }

    private static int ticket = 100;

    public static synchronized boolean dec() {
        if (ticket == 0) return false;
        ticket--;
        System.out.println("线程" + Thread.currentThread().getName() + " ticket 为:" + ticket);
        return true;
    }
}


前一篇:
后一篇:

发表评论