java多线程设计——线程启动,互斥,Single Threaded Execution
1.线程的启动
顺序,并发,并行
顺序:用于表示多个操作“依次处理”。比如把十个操作交给一个人处理,这个人就得一个一个地按顺序来处理
并行:用于表示多个操作“同时处理”。比如把十个操作交给两个人处理,这两个人就会并行处理。
并发:将操作打散成多个步骤,然后依次执行,就像是说一个人同时做好几件事,但是
他执行的动作是先做这件事,然后停下来再做另一件事。
实际上运行的线程就像上面这样在不断切换,顺序执行并发处理。
程序的终止:
Java程序的终止是指除守护线程以外的线程全部终止。守护线程是执行后台作业的线程。通过setDaemon()设置守护线程。
线程的启动1:Thread类继承
public class PrintThread extends Thread{
private String msg;
public PrintThread(String msg) {
super();
this.msg = msg;
}
public void run(){
for (int i = 0; i < 10000; i++) {
System.out.println(msg);
}
}
public static void main(String[] args) {
new PrintThread("God!").start();
new PrintThread("Nice!").start();
}
}
线程的启动2:Runnable接口实现
public class Printer implements Runnable {
private String msg;
public Printer(String msg) {
super();
this.msg = msg;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10000; i++) {
System.out.println(msg);
}
}
public static void main(String[] args) {
new Thread(new Printer("Good!")).start();
new Thread(new Printer("bad!")).start();
ThreadFactory factory = Executors.defaultThreadFactory();
factory.newThread(new Printer("XSM")).start();
}
}
利用ThreadFactory启动线程:
ThreadFactory factory = Executors.defaultThreadFactory();
factory.newThread(new Printer("XSM")).start();
线程的暂停:
Thread.sleep(1000);//暂停1s
2. 线程的互斥处理
多线程程序中的各个线程是自由运行的,所以他们有时会操作同一个案例
Synchronized方法处理互斥问题
Synchronized每次只能由一个线程执行,线程运行完synchornized方法后,释放锁
锁和监视:
获取锁有时叫做“拥有监视”或者“持有锁”
当前线程是否已获取某一对象的锁通过Thread.holdsLock方法确认,当前线程已获取对象obj的锁时,可使用assert来表示:
Assert Thread.holdsLock(obj);
每个实例都有独立的锁;如图bank1,bank2
synchronized代码块
Synchronized(表达式){
}
synchronized实例方法和synchronized代码块
Sychronzied void method(){
}
等效于
void method(){
Synchronized(this){
}
}
synchronized静态方法和synchronized代码块
synchronized静态方法是使用该类对象的锁来执行线程的互斥处理的,Somthing.class是Something类对应的java.lang.class类的实例
线程协作:
假如需要执行更精确的控制,而不是单纯的等待其他线程运行终止
例如:
如果空间为空则写入数据,如果非空则一直等待到变空为止
空间已为空时,“通知”正在等待的线程
wait方法:将线程放入 等待队列
如果要执行wait方法 ,线程必须持有锁,如图:
当线程A进入等待队列的时候,会释放锁,这个时候线程B就会获取到
notify方法---从等待队列中取出线程
notify 方法会将等待队列中的一个线程取出。如图
线程A退出等待队列,想要进入wait的下一个操作,但刚才执行notify的线程B仍痴有锁
刚才执行notify的线程B释放了锁
notifyAll----从等待队列中取出所有线程
概念小结:
某个线程在运行synchronized方法时,其他所有线程都会停止运行(错)
停止运行的只是想要获取同一个实例的锁的线程。
wait方法的调用必须在synchronized方法中(错)
调用wait方法的语句可以写在synchronized方法中和代码块中,或者二者调用的其他方法中,只要执行方法的线程在执行时获取了对象实例的锁即可。
3. Single Threaded Execution
private int counter = 0;
private String name = "Nobody";
private String address = "Nowhere";
public void pass(String name,String address){
this.counter++;
this.name = name;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.address = address;
check();
}
public String toStr(){
return "No." + counter+":"+name+","+address;
}
public void check(){
if(name.charAt(0)!= address.charAt(0)){
System.out.println("Broken"+toStr());
}
}
}
UserThread类:
public class UserThread extends Thread{
private final Gate gate;
private final String myname;
private final String myaddress;
public UserThread2(Gate gate, String myname, String myaddress) {
this.gate = gate;
this.myname = myname;
this.myaddress = myaddress;
}
public void run(){
System.out.println(myname+"begin");
while(true){
gate.pass(myname, myaddress);
}
}
}
public static void main{
Gate gate = new Gate();
new UserThread(gate, "Alice", "Asian").start();
new UserThread(gate, "Bobby", "Brazil").start();
new UserThread(gate, "Chris", "Canada").start();
this.counter++;
this.name = name;
this.address = address;
check();
}
解决方法:在pass()方法前加上synchronized
使用Single Threaded Execution模式的情况
1.多线程时
2.数据可被多个线程访问
3.状态可能改变
4.需要确保数据安全性
在使用Single Threaded Execution,会存在发生死锁的危险
1.存在多个SharedResource角色(参与者)
2.线程在持有着某个SharedResource角色的锁的同时,还想获取其他SharedResource角色的锁
3.获取SharedResource角色的锁的顺序并不固定
比喻两个意大利吃拉面的例子(两个人吃面只有一个勺子和叉子,但是勺子和叉子缺一不可,一个人拿着叉子,一个人拿着勺子):
1.存在多个SharedResource角色(参与者)相当于叉子和勺子
2.线程在持有着某个SharedResource角色的锁的同时,还想获取其他SharedResource角色的锁 相当于拿着叉子还想要勺子
3.获取SharedResource角色的锁的顺序并不固定 拿叉子和拿勺子的顺序并不一样
继承反复性:
对于多线程来说,继承会出现很多问题
.Single Threaded Execution 降低程序性能
1. 获取锁花费的时间
2. 线程冲突引起的等待
Semaphore的使用
semaphone.acquire()用于确认是否存在可用资源,当所有资源已被使用时,线程会阻塞在此方法中
semaphone.release()方法释放所用的资源
semaphone.avaliablePermits()表示当前正在使用的资源个数