多个线程之间共享数据,首先想到的是将共享数据设置为全局变量,并且用static修饰,但是static修饰的变量是类变量,生命周期太长了,占用内存,本文将介绍三种方法实现多个线程之间共享数据。
方法一:多个线程对共享数据的操作是相同的,那么创建
一个Runnable的子类对象,将这个对象作为参数传递给Thread的构造方法,此时因为多个线程操作的是同一个Runnable的子类对象,所以他们操作的是同一个共享数据。比如:买票系统,所以的线程的操作都是对票数减一的操作。
代码如下:
public class MutilThreadShareDate{
public static void main(String[] args) {
oneRunnable();
}
//买票系统
public static void oneRunnable(){
ShareDate1 date1 = new ShareDate1();
// 因为四个线程访问的是同一个date对象,所以数据之间可以共享
new Thread(date1).start();
new Thread(date1).start();
new Thread(date1).start();
new Thread(date1).start();
}
}
class ShareDate1 implements Runnable {
int j = 100;//共享变量
public synchronized void decrement() {
System.out.println(Thread.currentThread().getName() + ",做j--的操作," + j);
j--;
}
@Override
public void run() {
/*
* 怎么做到线程安全,保证,让票数大于0呢?
* 因为票数j属于共享数据,当j满足条件时进去while循环,while循环中加了锁,保证线程安全
* 当多个线程进入了while循环,在等待锁的时,别的线程对j进行了j--的操作,当j减到0时,等待的线程获得锁之后,还会继续做j--的操作,导致j为负数,所以要对j再次加一判断。
*/
while (j > 0) {
synchronized (this) {
if (j > 0) {
//让当前线程停下10ms,让出cpu的执行权,其他线程不能获得锁,但是可以运行不需要该锁的代码。10s中到了,就自动向下执行
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
decrement();
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
方法二:多个线程对共享数据的操作是不同的,将共享数据和操作共享数据的方法放在同一对象中,将这个对象作为参数传递给Runnable的子类,在子类中用该对象的方法对共享数据进行操作。如:生产者消费则。
代码如下:
public class MutilThreadShareDate{
public static void main(String[] args) {
twoRunnable2();
}
public static void twoRunnable2(){
final ShareDate1 date1 = new ShareDate1();
new Thread(new MyRunnable1(date1)).start();
new Thread(new MyRunnable2(date1)).start();
}
}
//创建两个Runnable的子类对象,对象接收一个参数,对这个参数进行操作,实现数据间的共享
class MyRunnable1 implements Runnable{
private ShareDate1 date1;
public MyRunnable1(ShareDate1 date1){
this.date1 = date1;
}
@Override
public void run() {
while(date1.j > 100){
date1.decrement();
}
}
}
//创建两个Runnable的子类对象,对象接收一个参数,对这个参数进行操作,实现数据间的共享
class MyRunnable2 implements Runnable{
private ShareDate1 date1;
public MyRunnable2(ShareDate1 date1){
this.date1 = date1;
}
@Override
public void run() {
while(date1.j < 200){
date1.increment();
}
}
}
//共享数据所在的类
class ShareDate1 implements Runnable {
int j = 100;
public synchronized void increment() {
System.out.println(Thread.currentThread().getName() + ",做j++的操作," + j);
j++;
}
public synchronized void decrement() {
System.out.println(Thread.currentThread().getName() + ",做j--的操作," + j);
j--;
}
@Override
public void run() {
/*
* 怎么做到线程安全,保证,票数大于0呢?
* 因为票数j属于共享数据,当j满足条件时进去while循环,while循环中加了锁,保证线程安全
* 当多个线程进入了while循环,在等待锁的时,别的线程对j进行了j--的操作,当j减到0时,等待的线程获得锁之后,还会继续做j--的操作,导致j为负数,所以要对j再次加一判断。
*/
while (j > 0) {
synchronized (this) {
if (j > 0) {
//让当前线程停下10ms,让出cpu的执行权,其他线程不能获得锁,但是可以运行不需要锁的代码。
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
decrement();
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
方法三:多个线程对共享数据的操作是不同的, 用内部类的方式去实现,创建Runnable的子类作为内部类,将共享对象作为全局变量,在Runnable的子类中对共享数据进行操作。
代码如下:
public class MutilThreadShareDate{
public static void main(String[] args) {
twoRunnable1();
}
public static void twoRunnable1(){
//内部类调用外部类的对象,外部类的对象必须用final修饰,保证内部类不能修改他。
final ShareDate1 date1 = new ShareDate1();
/*
* 因为这两个线程操作的是同一个对象,所以用的是同一个j,这个j在两个线程中间是共享的。
*/
new Thread(
new Runnable(){
@Override
public void run() {
date1.increment();
}
}
).start();
new Thread(
new Runnable(){
@Override
public void run() {
date1.decrement();
}
}
).start();
}
}
//共享数据所在的类
class ShareDate1 implements Runnable {
int j = 100;
public synchronized void increment() {
System.out.println(Thread.currentThread().getName() + ",做j++的操作," + j);
j++;
}
public synchronized void decrement() {
System.out.println(Thread.currentThread().getName() + ",做j--的操作," + j);
j--;
}
@Override
public void run() {
/*
* 怎么做到线程安全,保证,票数大于0呢?
* 因为票数j属于共享数据,当j满足条件时进去while循环,while循环中加了锁,保证线程安全
* 当多个线程进入了while循环,在等待锁的时,别的线程对j进行了j--的操作,当j减到0时,等待的线程获得锁之后,还会继续做j--的操作,导致j为负数,所以要对j再次加一判断。
*/
while (j > 0) {
synchronized (this) {
if (j > 0) {
//让当前线程停下10ms,让出cpu的执行权,其他线程不能获得锁,但是可以运行不需要锁的代码。
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
decrement();
}
}
}
}
}