1.多个线程访问共享数据的方式
多个线程访问共享数据分为两种方式:
1)每个线程执行操作共享数据的方式相同
2)每个线程执行操作共享数据的方式不同
2.多个线程执行操作共享数据的方式相同
如果每个线程执行操作共享数据的方式相同,那么可以使用同一个Runnable对象,将共享数据放在Runnable中并重写操作共享数据的run()方法。然后创建多个线程并将同一个Runnable对象作为参数传入线程的构造器中。例如售票系统。
//售票类
class Tickets implements Runnable {
//定义总票数为100
private int tickets = 100;
//重写run方法,封装运行代码
public void run() {
//循环售票
while(true) {
//同步代码块,使用本类字节码对象作为锁
synchronized(Tickets.class) {
//如果票数大于0,则可以继续出售。每售出一张,票数减一
if(tickets > 0) {
System.out.println(Thread.currentThread().getName() + "售出第" + (tickets--) + "号票");
}
}
}
}
}
public class TicketDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Tickets tickets = new Tickets();
//创建四个售票窗口
Thread t1 = new Thread(tickets);
Thread t2 = new Thread(tickets);
Thread t3 = new Thread(tickets);
Thread t4 = new Thread(tickets);
//开始售票
t1.start();
t2.start();
t3.start();
t4.start();
}
}
3.多个线程执行操作共享数据的方式不同
如果每个线程执行操作共享数据的方式不同,可以有3中方式实现:
1)将共享数据封装在一个对象中,然后将此对象逐一传递给各个不同的Runnable,每个Runnable的run()封装不同操作共享数据的方法。
例:设计4个线程,其中2个线程每次对j加1,另外两个线程每次对j减1。
//定义Data类封装数据j
class Data {
private int j = 0;
//对j进行加1的操作,因为要设计多线程访问,所以是同步方法
public synchronized void increment(){
System.out.println("对j加1后j的值为:" + (++j));
}
//对j进行减1的操作
public synchronized void decrement(){
System.out.println("对j减1后j的值为:" + (--j));
}
}
//定义MyRunnalbePlus对j进行加操作
class MyRunnalbePlus implements Runnable{
private Data data;
public MyRunnalbePlus(Data data){
this.data = data;
}
@Override
public void run() {
while(true){
data.increment();
}
}
}
//定义MyRunnalbeDec对j进行加操作
class MyRunnalbeDec implements Runnable{
private Data data;
public MyRunnalbeDec(Data data){
this.data = data;
}
@Override
public void run() {
while(true){
data.decrement();
}
}
}
public class MultiThreadShareData {
public static void main(String[] args) {
// TODO Auto-generated method stub
Data data = new Data();
//将同一个data作为参数传入Runnable对象
MyRunnalbePlus plus = new MyRunnalbePlus(data);
MyRunnalbeDec dec = new MyRunnalbeDec(data);
//分别开启两个加j和减j的线程
for(int i = 0; i < 2; i++){
new Thread(plus).start();
new Thread(dec).start();
}
}
}
2)将不同操作共享数据的Runnable作为某一个类的内部类,共享数据作为外部类的成员变量。
public class MultiThreadShareData {
//共享数据作为外部类成员变量
private static int j = 0;
//对j进行加1的操作,因为要设计多线程访问,所以是同步方法
public static synchronized void increment(){
System.out.println("对j加1后j的值为:" + (++j));
}
//对j进行减1的操作
public static synchronized void decrement(){
System.out.println("对j减1后j的值为:" + (--j));
}
//将Runnable定义为内部类
static class Inc implements Runnable{
@Override
public void run() {
while(true)
increment();
}
}
static class Dec implements Runnable{
@Override
public void run() {
while(true)
decrement();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建不同的Runnable
Inc inc = new Inc();
Dec dec = new Dec();
for(int i = 0; i < 2; i++){
new Thread(inc).start();
new Thread(dec).start();
}
}
}
3)上面两种方式的组合:将共享数据封装在一个对象中,每个线程对共享数据的操作也由该对象完成。对象作为外部类的成员变量,而Runnable定义为内部类。
//定义Data类封装数据j
class Data {
private int j = 0;
//对j进行加1的操作,因为要设计多线程访问,所以是同步方法
public synchronized void increment(){
System.out.println("对j加1后j的值为:" + (++j));
}
//对j进行减1的操作
public synchronized void decrement(){
System.out.println("对j减1后j的值为:" + (--j));
}
}
public class MultiThreadShareData {
//将共享数据作为类的成员变量
private static Data data = new Data();
public static void main(String[] args) {
// TODO Auto-generated method stub
//将不同操作共享数据的Runnable作为内部类。
//此处为匿名内部类
for(int i = 0; i < 2; i++){
new Thread(new Runnable(){
@Override
public void run() {
while(true)
data.increment();
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
while(true)
data.decrement();
}
}).start();
}
}
}