java timertask 安全_Java高新技术7_多线程1(Timer,TimerTask,ThreadLocal,传统多线程安全问题和通信)...

一.如果每个线程执行的代码相同,可以使用同一个Runnable接口子类对象,这个Runnable接口子类对象中有那个共享数据,例如,买票系统就可以这么做。

二.如果每个线程执行的代码不同,这时候需要用不同的Runnable接口子类对象,有如下两种方式来实现这些Runnable接口子类对象之间的数据共享:

1.将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable接口子类对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信。

2.将这些Runnable接口子类对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable接口子类对象调用外部类的这些方法。

3.上面两种方式的组合:将共享数据封装在另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部变量,每个线程的Runnable接口子类对象作为外部类中的成员内部类或局部内部类。

总之,要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥和通信。

//使用方式一

class Ticket implementsRunnable{private int ticket=100;

@Overridepublic synchronized voidrun() {//TODO 自动生成的方法存根

while(true)if(ticket>0)

System.out.println(Thread.currentThread().getName()+"..."+ticket—);

}

}classTicketTest{public static voidmain(String[] args){

Ticket t=newTicket();newThread(t).start();newThread(t).start();

}

}

//方式二:1

classResource{private int j=0;public synchronized voidadd(){

j=j+1;

System.out.println(Thread.currentThread().getName()+"..."+j);

}public synchronized voidreduce(){

j=j-1;

System.out.println(Thread.currentThread().getName()+"..."+j);

}

}class addImp implementsRunnable{privateResource r;public addImp(Resource r){//将Resource对象传递过来

this.r=r;

}

@Overridepublic voidrun() {//TODO 自动生成的方法存根

r.add();

}

}class reduceImp implementsRunnable{privateResource r;public reduceImp(Resource r){//将Resource对象传递过来

this.r=r;

}

@Overridepublic voidrun() {//TODO 自动生成的方法存根

r.reduce();

}

}classMainClass{public static voidmain(String[] args){

Resource r=new Resource();//用的依然是方式一定义的Resource类

for(int i=0;i<2;++i)new Thread(newaddImp(r)).start();for(int i=0;i<2;++i)new Thread(newreduceImp(r)).start();

}

}

//方式二:2

classMainClass2{private static int j=0;//共享数据作为这个外部类中的成员变量

public static synchronized void add(){//每个线程对共享数据的操作方法也分配给外部类

j=j+1;

System.out.println(Thread.currentThread().getName()+"..."+j);

}public static synchronized voidreduce(){

j=j-1;

System.out.println(Thread.currentThread().getName()+"..."+j);

}public static void main(String[] args){//这里静态只能访问静态,以上成员需要static修饰符,根据需要

for(int i=0;i<2;++i){new Thread(newRunnable(){

@Overridepublic voidrun() {

add();

}

}).start();new Thread(newRunnable(){

@Overridepublic voidrun() {

reduce();

}

}).start();

}

}

}

//方式2:3

classMultithreadShare7 {private static Resource r=newResource();public static voidmain(String[] args){//final Resource r=new Resource();//r作为局部变量,被内部类访问需要final修饰

for(int i=0;i<2;++i){new Thread(newRunnable(){

@Overridepublic voidrun() {

r.add();

}

}).start();new Thread(newRunnable(){

@Overridepublic voidrun() {

r.reduce();

}

}).start();

}

}

}

线程间通信例子:

packagecom.itheima.thread;/*子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程循环

100,如此循环50次,请写出程序*/

//使用的3思想

classRunCode{private boolean flag=false;//使用标记进一步控制

public synchronized voidsubThreadCode(){while(flag)try{this.wait();

}catch(InterruptedException e) {

e.printStackTrace();

}for(int i=0;i<5;++i)

System.out

.println(Thread.currentThread().getName()+ "..." +i);

flag=true;this.notify();

}public synchronized voidmainThreadCode(){while(!flag)try{this.wait();

}catch(InterruptedException e) {//TODO 自动生成的 catch 块

e.printStackTrace();

}for(int i=0;i<3;++i)

System.out

.println(Thread.currentThread().getName()+ "..." +i);

flag=false;this.notify();

}

}public classThreadInterviewQuestion4 {/***@paramargs*/

public static voidmain(String[] args) {final RunCode rc=newRunCode();new Thread(newRunnable(){

@Overridepublic voidrun() {for(int i=0;i<10000;++i){//没有按照原题目,为了看是否有”奇迹”发生 rc.subThreadCode();

}

}

}).start();for(int i=0;i<10000;++i){

rc.mainThreadCode();

}

}

}/*规范代码:

1.多个线程执行代码放在共享资源中(这样做便于管理,扩展)

2.等待唤醒机制一般都要使用标记

3.尝试各种方法,发现最好使用if判断是否wait,然后线程执行代码,置换标记,唤醒(其它方式各种"奇迹") 4.即使两个线程进行通信,依然建议while判断标记,api中一句话:对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用更加安全*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值