第六章 线程Thread
第一节 线程
马克-to-win:程序,进程和线程的区别是什么?这个问题比较抽象难理解,但又非常重要。我并不想给出一大堆抽象的学术解释,那样只能误国误民。所以我先给大家举一个例子。马克-to-win: 2000年的时候,我比较爱用ie的老版本。当时我喜欢边上网边下载很多东西,比如很多MP3同时下。我发觉如果我打开一个ie,之后用file/new,new出很多窗口来,边看网页,边下载很多mp3的话,如果有一个下载崩溃的话,所有的ie窗口就同时都崩溃了,包括网页和所有的下载窗口。马克-to-win:后来我就学聪明了,我打开两个ie。一个ie用来浏览网页。另一个ie,file/new出很多新的窗口。这样如果下载出问题了,下载的ie会崩溃。但浏览网页的ie依旧完好的工作。在上述例子当中,ie就是一个应用程序,后来我打开两个ie,就是打开两个进程。这两个进程,在内存中分别占有不同的代码空间。马克-to-win:所以一个进程崩溃不影响另外一个。后来从其中一个ie, file/new出很多个新窗口。每一个窗口就是一个线程,线程在内存当中是没有自己的代码空间的。它只能依附于进程存在。马克-to-win:所以,这个进程当中的一个线程窗口崩溃了,所有依附于这个进程的线程窗口就都崩溃了。相对于进程来讲,线程非常轻量,非常节省资源。我经常同时打开二十个窗口,下载各种音乐mp3。反正是线程,不占资源。马克-to-win:线程在内存当中没有自己的代码空间。只有程序计数器。一个线程可能执行到所依附进程的1000行,另一个线程,可能执行到第99行,这两个线程,虽然依附于同一个主进程,但他们各自执行各自的,相互不影响。马克-to-win:仔细揣摩我上面说的故事,你就会理解,程序,进程和线程的区别。给点抽象的话:程序是硬盘上的一个文件,是一个机器代码和它的数据的集合。进程是程序在内存上的一次运行活动,占代码空间。线程是依附于进程,靠程序计数器能独立运行,轻量独立运行单元。
线程间(因为使用程序计数器)的切换成本比进程间切换成本低,所以使系统的空转时间少,提高CPU利用率。
新建 (new或born) : 马克-to-win: new出线程对象,还没start呢, 处于新建状态
就绪或说可运行(ready或runnable): 马克-to-win: 在start()之后,它将处于就绪状态或可运行状态,但cpu还没分配给它呢,所以还没真正运行呢。通过后面的学习可知:sleep(),join(),IO请求,同步锁释放等很多操作之后, 真正运行之前,都会回到这个状态。
运行 (Running) : 获取到了cpu,可以真正运行了, run()里的代码被运行。
阻塞 (Blocked) – 因为某种原因暂时停止运行。wait(),获取对象的同步锁之前,sleep(),join(),或者发出了I/O请求时。
死亡 (Dead) – 在run()方法已完成执行(或break,return,异常)或其 stop() 方法被调用之后(sun公司已不推荐使用,因为中断得太狠,容易引起同步问题),线程就处于死亡状态。
5.线程间互动
i)停止(stop)一个线程(靠着return, break,或异常手段) (视频下载) (全部书籍)
马克-to-win:java的官方文档说不要用stop方法来停止一个线程。因为stop方法太狠,太极端,会出现同步问题,使数据不一致。所以我们会通过设置标志,通过return, break,异常等手段来控制流程自然停止。
例:1.5.1-本章源码
class MyThreadMark_to_win extends Thread{输出结果:
i = 0
i = 1
退出了
后续:
马克-to-win:如上一节例子所说: 主线程和子线程同时开始运行,主线程睡了300毫秒以后,开始把子线程类成员stop给设成真。子线程睡了两次200毫秒后正好赶上stop为真,就return了!因为没有后续程序,这个线程就结束了。
把上面的程序return,变成自己通过throw主动抛出异常,结果是一样的。 (视频下载) (全部书籍)
例:1.5.1_1-本章源码
class MyThreadMark_to_win extends Thread{
private boolean stop;
public void run() {
for (int i = 0; i < 100; i++) {
if (stop) {
System.out.println("退出了");
throw new ArithmeticException("divide by 0");
}
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("i = " + i);
}
}
public void setStop(boolean stop) {
this.stop = stop;
}
}
public class Test {
public static void main(String[] args) {
MyThreadMark_to_win mt = new MyThreadMark_to_win();
mt.start();
try {
Thread.sleep(300);
} catch (Exception e) {
}
mt.setStop(true);
}
}
输出结果:
i = 0
Exception in thread "Thread-0" java.lang.ArithmeticException: divide by 0
at MyThreadMark_to_win.run(Test.java:7)
i = 1
退出了
ii)停止(stop)一个线程(靠interrupt手段) (视频下载) (全部书籍)
例:1.5.2-本章源码
class ThreadMark_to_win extends Thread {输出结果:
i = 0
i = 1
我被打断
后续:
马克-to-win:本例中,主线程和子线程同时开始。主线程睡了250毫秒以后,开始打断子线程。子线程每睡一百毫秒 就打印一下。刚睡了两次打印出0 和1以后,就被主线程打断了。马克-to-win:mt.interrupt(); 意味着进入到mt那个线程中,抛出一个InterruptedException异常,这样当然mt那个线程的catch能捕获到了。
下面的例子证明,如果在子线程中开始不用 try {
wait();
} catch (InterruptedException e) {
}
例:1.5.2_1-本章源码
class ThreadMark_to_win extends Thread {
Thread mainT;
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("我是子线程,被打断");
return;
}
mainT.interrupt();
}
public void setMainThread(Thread t1) {
mainT = t1;
}
}
public class Test {
public static void main(String[] args) {
Thread mainT = Thread.currentThread();
ThreadMark_to_win st = new ThreadMark_to_win();
st.setMainThread(mainT);
st.start();
try {
Thread.sleep(250);
} catch (InterruptedException e) {
System.out.println("我是主线程,被打断");
}
}
}
例:1.5.2_2-本章源码
class ThreadMark_to_win extends Thread {马克-to-win:join的意思就是本线程停下来,(视频下载) (全部书籍)等着另外一个线程完事,之后执行本线程的下一句话。(感觉有点像过去张三等着李四,等到后join在一起一块继续走)下面给出了一个主线程要join一个子线程的例子。
例:1.5.3-本章源码
class ThreadMark_to_win extends Thread {
int e;
public void run() {
for (int i = 0; i < 4; i++) {
e = e + i;
}
System.out.println("完成");
}
}
public class Test {
public static void main(String[] args) {
ThreadMark_to_win tm = new ThreadMark_to_win();
tm.start();
try {
/*本线程停在这儿等着tm线程结束,接着执行本线程下面的程序*/ tm.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
/*注意虽然tm线程结束了,只是它作为线程的状态变成了结束,但是tm作为实例还存在, 你并没有tm=null,(如果你tm=null,之后执行tm.e,会报空指针异常,)线程的状态和实例是两码事。*/
System.out.println("e = " + tm.e);
}
}
输出结果:
完成
e = 6
例:1.5.3_1-本章源码
class ThreadMark_to_win extends Thread {例:1.5.3_2-本章源码
class ThreadMark_to_win extends Thread {java中线程的优先级用1-10之间的数字表示,数值越大优先级越高,默认的优先级为5。Java中的线程优先级是在Thread类中定义的常量
NORM_PRIORITY : 值为5,MAX_PRIORITY :值为10,MIN_PRIORITY : 值为1,缺省优先级为 NORM_PRIORITY。有关优先级的常用方法有两个:1)final void setPriority(int newp) : 修改线程的当前优先级
2)final int getPriority() : 返回线程的优先级。马克-to-win:线程的优先级不能担保线程的执行次序。优先级高的线程获取CPU执行的几率较大,优先级低的线程也有机会执行。参考http://www.javamex.com/tutorials/threads/priority_what.shtml其中有句:there'd quite possibly be lower-priority threads that barely got any CPU at all, being continually starved by higher-priority threads that needed CPU. So Windows has a fallback mechanism, whereby a thread that hasn't run for a long time is given a temporary priority boost.大致意思:为防止低优先级的线程被饿死,Windows有个抗争的方法, 给低优先级的线程一个优先级的临时提升。。。。。。更多的请大家参考此网站。
例:1.6.1-本章源码
class ThreadMark_to_win extends Thread {
static boolean go=true;
private String s;
int i;
public ThreadMark_to_win(String s) {
this.s = s;
}
public void run() {
while(go){
System.out.println(s+" 到了 "+i++);
try {
this.sleep(1);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
public class Test {
public static void main(String[] args) {
Thread t1 = new ThreadMark_to_win("线程1");
Thread t2 = new ThreadMark_to_win("线程2");
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadMark_to_win.go=false;
}
}
输出结果:
线程1 到了 0
线程2 到了 0
线程1 到了 1
线程2 到了 1
线程2 到了 2
线程1 到了 2
线程2 到了 3
线程1 到了 3
线程2 到了 4
线程1 到了 4
线程2 到了 5
线程1 到了 5
线程2 到了 6
线程1 到了 6
。
。
。
。
。
。
。
线程1 到了 3335
线程2 到了 4753
线程2 到了 4754
线程2 到了 4755
线程2 到了 4756
线程1 到了 3336
线程2 到了 4757
线程2 到了 4758
线程2 到了 4759
7.精灵线程(Daemon)或守护线程: (视频下载) (全部书籍)
马克-to-win:Daemon英文意思是希腊神话中半人半神的精灵,守护神。在java中,"精灵守护Daemon线程"就是运行在程序后台的线程,一般被用于在后台为其它线程提供服务。既然它在后台运行,当前台线程(前几节学习的线程)运行完,主体程序就结束了,理所当然该后台线程也应该随之结束了。相对来讲,前面几节我们讲的线程是"用户线程",这两种线程技术上来讲有什么分别呢?java官方文档中大致这样描述:The Java Virtual Machine continues to execute threads until All threads that are not daemon threads have died。 这句话的含义就是:用户线程不完,jvm系统就不完,要是想只运行"精灵Daemon线程",对不起jvm不给面子,不伺候,就关闭了,不给"精灵Daemon线程"们单独运行的机会。这句话比较难理解,我换一句话来说这件事。当一个应用程序的所有非精灵线程停止运行时,即使仍有精灵线程还在运行,该应用程序也将终止,反过来,只要还有非精灵线程在运行,应用程序就不会停止。我们可以通过setDaemon(boolean on)来设置某线程为精灵线程。用isDaemon()来判断某线程是否为精灵线程或守护线程。注意:要想设置一个线程为精灵守护线程,setDaemon必须在start前调用。例:1.7.1_1-本章源码
class ThreadMark_to_win extends Thread {
public void run(){
for(int i = 1; i <= 15;i++){
try{
Thread.sleep(100);
} catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println("子线程 "+i);
}
}
}
public class Test extends Thread{
public static void main(String [] args){
ThreadMark_to_win tm = new ThreadMark_to_win();
tm.setDaemon(true);
tm.start();
System.out.println("子线程是精灵线程吗?" +tm.isDaemon());
try{
Thread.sleep(1000);
} catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"已经结束");
}
}
输出结果:
子线程是精灵线程吗?true
子线程 1
子线程 2
子线程 3
子线程 4
子线程 5
子线程 6
子线程 7
子线程 8
子线程 9
main已经结束
子线程 10
后续:马克-to-win:注意上面主线程一结束,精灵线程立刻玩儿完。相对来讲,我们看一个非精灵线程的对等例子。
例:1.7.1_2-本章源码
class ThreadMark_to_win extends Thread {
public void run(){
for(int i = 1; i <= 15;i++){
try{
Thread.sleep(100);
} catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println("子线程 "+i);
}
}
}
public class Test extends Thread{
public static void main(String [] args){
ThreadMark_to_win tm = new ThreadMark_to_win();
// tm.setDaemon(true);
tm.start();
System.out.println("子线程是精灵线程吗?" +tm.isDaemon());
try{
Thread.sleep(1000);
} catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"已经结束");
}
}
什么是线程安全? 马克-to-win: (视频下载) (全部书籍)最大的大白话,你的代码一个线程执行挺好,一上多线程测试就玩儿完(结果不是你所想要的),这就是线程不安全。反之为线程安全。首先,我们把第二章讲单态模式或单例模式(Singleton)的例子再搬过来一次,但这里把一些无关的打印和注释去掉了:
class Photoshop {
private Photoshop() {
}
private static Photoshop photoshop = null;// 这个值独立于任何对象存在,实例化任何对象之前,这个成员就有可能有值。
public static Photoshop getInstanceQixy() {
if (photoshop == null) {
photoshop = new Photoshop();
}
return photoshop;
}
}
public class Test {
public static void main(String[] args) {
Photoshop photoshopI1 = Photoshop.getInstanceQixy();
Photoshop photoshopI2 = Photoshop.getInstanceQixy();
System.out.println(photoshopI1+" "+photoshopI2);
}
}
后序:上面的例子一切都正常,就是一个非常普通的单态模式的实现。但要想上面的例子正确运行,我们必须确保运行环境是单线程的。如果运行环境是多线程的,以上的单态模式的实现,就有一定的机率,运行得不到正确的结果了。以下我用实验(下面的例子)来说明我这一论点。
例:1.8.1_b-本章源码
class Photoshop {
private Photoshop() {
}
private static Photoshop photoshop = null;
public static Photoshop getInstanceQixy() {
if (photoshop == null) {
photoshop = new Photoshop();
}
return photoshop;
}
}
class MyThreadMark_to_win extends Thread {
public void run() {
Photoshop photoshopI1 = Photoshop.getInstanceQixy();
System.out.println(Thread.currentThread().getName() + "实例是 "
+ photoshopI1);
}
}
public class Test {
public static void main(String[] args) {
MyThreadMark_to_win mt1 = new MyThreadMark_to_win();
MyThreadMark_to_win mt2 = new MyThreadMark_to_win();
mt1.start();
mt2.start();
}
}
后序:因为两个线程同时启动,如果一个线程执行完photoshop = new Photoshop();以后,另外一个线程执行if (photoshop == null)判断,则只会得到一个photoshop实例。然而对于得到了两个photoshop实例结果的这种情况,一定是这两个线程同时执行if (photoshop == null)这句指令造成的。而线程的执行顺序和速度是我们人为不可控的。这就是程序得到以上两种结果的原因。既然你的目的是编一个单例的程序,单线程时结果正确,而在多线程执行环境时,结果得到了两个实例,(结果非预期),这种情况就说,我们编的代码Photoshop类是线程不安全的。马克-to-win:如果你确定你的代码不会在多线程的环境下执行,线程不安全的代码也没关系,因为通常情况下解决线程不安全要用synchronized,会影响性能。如果你确定你的代码不会。。。。。更多内容,进入:
输出结果:
main before10
main after 9
main before9
main after 8
main before8
main after 7
main before7
main after 6
main before6
main after 5
main before5
main after 4
main before4
main after 3
main before3
main after 2
main before2
main after 1
main before1
main after 0
class BookMark_to_win {
int bookNum=1;
void onlySellOne() {
if (bookNum > 0) {
System.out.println(Thread.currentThread().getName()
+ " before" + bookNum);
bookNum--;
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName()
+ " after " + bookNum);
}
}
}
class MyThread extends Thread {
BookMark_to_win book;
MyThread(BookMark_to_win tmp) {
this.book = tmp;
}
public void run() {
while (book.bookNum>0) {
book.onlySellOne();
}
}
}
public class Test {
public static void main(String[] args) {
BookMark_to_win bookM = new BookMark_to_win();
Thread t1 = new MyThread(bookM);
Thread t2 = new MyThread(bookM);
t1.start();
t2.start();
}
}
输出结果:
Thread-0 before1
Thread-1 before1
Thread-1 after -1
Thread-0 after -1
后续:我们仔细观察会发现:Thread-0 before1
Thread-0 after -1, 线程0之前读出有1本书,调用了onlySellOne后,里面只做了一次"bookNum--"操作,发现结果是“Thread-0 after -1”即为还剩-1本书。为什么1-1=-1呢?原来线程0调用onlySellOne的"bookNum--";时,线程1正好也执行到这, 调用了"bookNum--"; 所以实际上是1-1-1=-1;既然我们预期"bookNum--"是每次只卖一本书,单线程环境执行挺好,而在多线程环境下,得到了一次减两本的结果,典型属于线程不安全。
9.线程同步(synchronized)
马克-to-win:从上节我们学到,(视频下载) (全部书籍)当多个线程访问且更改同一个变量 时,很容易出现线程安全问题,诚然,我们可以通过一些其他手段,比如局部变量,多个实例,调整程序结构来解决线程安全问题,但是通常来讲,通过同步机制 synchronized来解决线程安全问题更加确定。比如,由于需求等其他限制条件决定,我们不能够用局部变量或多个实例或什么其他办法解决怎么办? synchronized为我们提供了比较确定的方法。换句话说,线程安全问题, synchronized基本能解决。分析上一节的线程安全问题,我们发现问题的起因主要是两个线程同时访问更改共同的变量造成的,只要我们让能够更改共 同变量的方法序列的执行,(换句话就是一个执行完后,另一个再执行,) 就没问题了。如何实现呢? 用synchronized, 现在针对上一节有问题的例子:1.8.1_b,我们只加一个字synchronized, 问题就解决了,例1.9.1-本章源码
class Photoshop {
private Photoshop() {
}
private static Photoshop photoshop = null;
public synchronized static Photoshop getInstanceQixy() {
if (photoshop == null) {
photoshop = new Photoshop();
}
return photoshop;
}
}
class MyThreadMark_to_win extends Thread {
public void run() {
Photoshop photoshopI1 = Photoshop.getInstanceQixy();
System.out.println(Thread.currentThread().getName() + "实例是 "
+ photoshopI1);
}
}
public class Test {
public static void main(String[] args) {
MyThreadMark_to_win mt1 = new MyThreadMark_to_win();
MyThreadMark_to_win mt2 = new MyThreadMark_to_win();
mt1.start();
mt2.start();
}
}
输出结果:
Thread-1实例是 Photoshop@a62fc3
Thread-0实例是 Photoshop@a62fc3
class BookMark_to_win {
int bookNum=10;
synchronized void onlySellOne() {
if (bookNum > 0) {
System.out.println(Thread.currentThread().getName()
+ " before" + bookNum);
bookNum--;
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName()
+ " after " + bookNum);
}
}
}
class MyThread extends Thread {
BookMark_to_win book;
MyThread(BookMark_to_win tmp) {
this.book = tmp;
}
public void run() {
/*run()里不能就只是写book.onlySellOne(), 因为会呈现
两个线程在那交替的效果*/
while (book.bookNum>0) {
book.onlySellOne();
}
}
}
public class Test {
public static void main(String[] args) {
BookMark_to_win bookM = new BookMark_to_win();
Thread t1 = new MyThread(bookM);
Thread t2 = new MyThread(bookM);
t1.start();
t2.start();
}
}
输出结果:
Thread-0 before10
Thread-0 after 9
Thread-0 before9
Thread-0 after 8
Thread-0 before8
Thread-0 after 7
Thread-0 before7
Thread-0 after 6
Thread-1 before6
Thread-1 after 5
Thread-1 before5
Thread-1 after 4
Thread-0 before4
Thread-0 after 3
Thread-0 before3
Thread-0 after 2
Thread-0 before2
Thread-0 after 1
Thread-0 before1
Thread-0 after 0
既然有关监视器monitor的概念比较难,大家怎么解释的都有。首先我给出一下java的官方文档,也是最权威的解释:
Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor."),Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them.
源自:http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
根据官方文档,我来说说我的看法。马克-to-win: synchronized
工作机制是这样的:Java中每个对象都有一把锁与之相关联,锁控制着对象的synchronized代码。一个要执行对象的synchronized代
码的线程必须先获得那个对象的锁。(即使两个方法分别被冠以synchronized,见例子例1.9.3-b)有点儿监控(monitor)的感觉吗?
synchronized关键字使用方式有两种:synchronized方法和synchronized块。以下会给出例子:
例1.9.3-本章源码class A {
public synchronized void f1() {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println("i = " + i);
}
}
}
class MyThread extends Thread {
A a;
public MyThread(A a) {
this.a = a;
}
public void run() {
a.f1();
}
}
public class TestMark_to_win {
public static void main(String[] args) {
A a = new A();
Thread t1 = new MyThread(a);
Thread t2 = new MyThread(a);
t1.start();
t2.start();
}
}
运行结果是
class A {
public void disp() {
System.out.println("新线程马克-to-win启动:");
for (int i = 0; i < 10; i++) {
System.out.println(i);
try {
Thread.sleep(500);
} catch (Exception e) {
}
}
}
}
public class TestMark_to_win extends Thread {
A a;
public TestMark_to_win(A a) {
this.a = a;
}
public void run() {
a.disp();
}
public static void main(String[] args) {
A a = new A();
TestMark_to_win t1 = new TestMark_to_win(a);
TestMark_to_win t2 = new TestMark_to_win(a);
t1.start();
t2.start();
}
}
例1.9.4_b-本章源码
class A {
public void disp() {
synchronized (this) {
System.out.println("新线程马克-to-win启动:");
for (int i = 0; i < 10; i++) {
System.out.println(i);
try {
Thread.sleep(500);
} catch (Exception e) {
}
}
}
}
}
public class TestMark_to_win extends Thread {
A a;
public TestMark_to_win(A a) {
this.a = a;
}
public void run() {
a.disp();
}
public static void main(String[] args) {
A a = new A();
TestMark_to_win t1 = new TestMark_to_win(a);
TestMark_to_win t2 = new TestMark_to_win(a);
t1.start();
t2.start();
}
}
新线程启动:
0
1
2
3
4
5
6
7
8
9
新线程启动:
0
1
2
3
4
5
6
7
8
9
下面给出一个例子,说明一个class中有两个方法synchronized的情况。它们互相阻挡的用法和上面的“一个方法有synchronized”的情况是一样的。
例1.9.5:
class A {
public synchronized void f1() {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println("f1 i = " + i);
}
}
public synchronized void f2() {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println("f2 i = " + i);
}
}
}
class MyThread1 extends Thread {
A a;
public MyThread1(A a) {
this.a = a;
}
public void run() {
a.f1();
}
}
class MyThread2 extends Thread {
A a;
public MyThread2(A a) {
this.a = a;
}
public void run() {
a.f2();
}
}
public class TestMark_to_win {
public static void main(String[] args) {
A a = new A();
Thread t1 = new MyThread1(a);
Thread t2 = new MyThread2(a);
t1.start();
t2.start();
}
}
输出结果:
f1 i = 0
f1 i = 1
f1 i = 2
f2 i = 0
f2 i = 1
f2 i = 2
上面两个synchronized的方法如其中一个无限循环,一定会挡住其他的方法。下面的例子先进f1的线程死死挡住想进f2的线程。
例1.9.5_b:
class A {
public synchronized void f1() {
//快速无限循环,别的线程什么也做不了
while (true) {
}
}
public synchronized void f2() {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println("f2 i = " + i);
}
}
}
class MyThread1 extends Thread {
A a;
public MyThread1(A a) {
this.a = a;
}
public void run() {
a.f1();
}
}
class MyThread2 extends Thread {
A a;
public MyThread2(A a) {
this.a = a;
}
public void run() {
a.f2();
}
}
public class TestMark_to_win {
public static void main(String[] args) {
A a = new A();
Thread t1 = new MyThread1(a);
Thread t2 = new MyThread2(a);
t1.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
t2.start();
}
}
结果什么也输不出来
class A {
private Object lock1 = new Object();
private Object lock2 = new Object();
public void f1() {
synchronized (lock1) {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在无限耗用你的CPU,eclipse的红灯还在亮");
}
}
}
public void f2() {
synchronized (lock2) {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println("f2 i = " + i
+ Thread.currentThread().getName());
}
}
}
}
class MyThread1 extends Thread {
A a;
public MyThread1(A a) {
this.a = a;
}
public void run() {
a.f1();
}
}
class MyThread2 extends Thread {
A a;
public MyThread2(A a) {
this.a = a;
}
public void run() {
a.f2();
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
Thread t1 = new MyThread1(a);
Thread t11 = new MyThread1(a);
Thread t2 = new MyThread2(a);
t1.start();
t11.start();
t2.start();
}
}
输出结果:
例1.9.6:
class A {
public synchronized void f1() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("f1模仿select * from table for update,执行的很慢"+Thread.currentThread().getName());
}
}
class MyThread1 extends Thread {
A a;
public MyThread1(A a) {
this.a = a;
}
public void run() {
a.f1();
}
}
public class TestMark_to_win {
public static void main(String[] args) {
MyThread1[] threads = new MyThread1[3];
A a = new A();
for (int i = 0; i < 3; i++) {
threads[i] = new MyThread1(a);
threads[i].start();
}
}
}
输出结果:
下面程序的concuNum会记录,现在队列里多少人在排队。selectForUpdateIntel就成了智能版的select * from table for update,人少我就排队,人多我就直接撤。
运行结果:
import java.util.concurrent.locks.ReentrantLock;
class A {
private ReentrantLock lock = new ReentrantLock();
int ticketNum = 10;
public void buyOne() throws InterruptedException {
System.out.println("just before lock.lockInterruptibly();");
/*lock.lockInterruptibly();的意思就是,当前线程获取了一把可打断的锁。当有n个thread同时执行到这句时,只有第一个thread能获得这个lock,其他thread都必须挡在那,在后边排队。catch不能放在本级方法调用中,否则当lock被打断后,继续优雅执行,lock.unlock();被执行时,就会出现lock状态不对的问题(Exception in thread java.lang.IllegalMonitorStateException,报完这个exception后,会在lock.unlock()这句话直接崩溃不能优雅结束),因为lock已经被打断了。换句话说,lock一旦被打断,必须确保lock.unlock()不能被执行。*/
lock.lockInterruptibly();
System.out.println(Thread.currentThread().getName() + "ticketNum is"
+ ticketNum);
if (ticketNum > 0) {
ticketNum--;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("模仿select * from table for update,执行的很慢,买了一张"
+ Thread.currentThread().getName() + "ticketNum is"
+ ticketNum);
}
lock.unlock();//释放锁
}
public void buyBatch(int num) throws InterruptedException {
System.out.println("just before lock.lockInterruptibly();");
lock.lockInterruptibly();
System.out.println("Thread.currentThread().getName()+ticketNum is"
+ ticketNum);
if (ticketNum >= num) {
ticketNum = ticketNum - num;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("模仿select * from table for update,执行的很慢,买了几张"
+ Thread.currentThread().getName() + "ticketNum is"
+ ticketNum);
}
lock.unlock();
}
}
class MyThread1 extends Thread {
A a;
public MyThread1(A a) {
this.a = a;
}
public void run() {
try {
a.buyOne();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "取消一张");
System.out.println(e);
}
}
}
class MyThread2 extends Thread {
A a;
public MyThread2(A a) {
this.a = a;
}
public void run() {
try {
a.buyBatch(3);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "取消几张");
System.out.println(e);
}
}
}
public class TestMark_to_win {
public static void main(String[] args) throws InterruptedException {
MyThread1[] threads = new MyThread1[6];
A a = new A();
for (int i = 0; i < 6; i++) {
threads[i] = new MyThread1(a);
}
MyThread2 myThread2 = new MyThread2(a);
threads[0].start();
threads[1].start();
threads[2].start();
threads[3].start();
threads[4].start();
myThread2.start();
threads[5].start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threads[4].interrupt();
threads[2].interrupt();
}
}
ReentrantLock类的tryLock和tryLock(时间) (视频下载) (全部书籍)
马 克-to-win:tryLock的方法就是试一下,如果能得到锁,就返回真,如果当时得不到,马上就返回假,绝不等。tryLock(时间)的用法就是 在规定的时间内设法得到锁。如果在规定的时间内最终不能得到锁,就返回假。注意,这个方法是可以被打断的,打断后的处理方法和上面的例子 lockInterruptibly的处理一样。(这种情况是tryLock(2, TimeUnit.SECONDS);根本没得到锁)运行结果:
例1.9.8_b:(只需要把上面实验的主程序改变一下就行,其他都不用变。)
public class TestMark_to_win {
public static void main(String[] args) throws InterruptedException {
MyThread1[] threads = new MyThread1[2];
A a = new A();
for (int i = 0; i < 2; i++) {
threads[i] = new MyThread1(a);
}
MyThread2 myThread2 = new MyThread2(a);
threads[0].start();
Thread.sleep(50);
myThread2.start();
threads[1].start();
Thread.sleep(50);
myThread2.interrupt();
}
}
(这种情况是tryLock(2, TimeUnit.SECONDS);正要获得锁的过程当中被打断了)运行结果:
just before lock.lockInterruptibly();例1.9.8_c:
public class TestMark_to_win {
volatile关键字与原子操作
我们先简要了解一下java虚拟机的内存模型。就像数据从物理内存拷贝到cpu高速缓存,进行操作完,再把数据返回到内存一样,为了屏蔽CPU高速缓存和
内存复杂细节且赢得跨平台的效果,java把所有的变量都存在主存(相当于物理内存)当中,每个线程都有自己的工作内存(相当于CPU高速缓存)。线程在
自己的工作内存做操作,不能直接对主存进行操作,最后把结果返回到主存。如果一个变量有volatile(易变的意思)修饰词,这意味着当有一个线程修改了这个变量,系
统会把工作内存当中的变化强制立刻反应在主存当中。其他线程要想读这个变量,也会被强迫读变化了的新值。volatile其实就保证了此变量无论怎么变,
任何线程看都是最新的。当两个线程,根据一个共同的信号,做互动时,一定要加volatile,保证这个信号是最新的。
volatile,有人说能够控制程序的语句有序性,但jvm并不能保证在所有的平台上都能够做到这一点,所以我的书中
就不赘述了。既然volatile控制程序语句的有序性不能保证所有的平台都正确运行,基于它的技术“双重检查锁”创建单态对象也就变得不可靠了,本书也
就不覆盖了。
就
是无法被别的线程打断的操作。要么不执行,要么就执行成功。例如:x=3是原子操作。过程就是先把工作内存的x赋成3,再把主存的x赋成3。y=x不是原
子操作,它涉及在工作内存先把x值读出来,再把这个值赋给y。x++或x=x+1也不是原子操作,它涉及取值,自加和赋值。下面我们就用一个例子来说明x
++不是原子操作所带来的问题。
class NumContainer {
int num;
}
class MulThreMarkToWin extends Thread {
NumContainer nc;
public void increase() {
nc.num++;
}
public MulThreMarkToWin(NumContainer nc) {
this.nc = nc;
}
public void run() {
increase();
}
}
public class TestMark_to_win {
public static void main(String[] args) {
NumContainer nc = new NumContainer();
MulThreMarkToWin[] threads = new MulThreMarkToWin[10000];
for (int i = 0; i < 10000; i++) {
threads[i] = new MulThreMarkToWin(nc);
}
for (int i = 0; i < 10000; i++) {
threads[i].start();
}
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(nc.num);
}
}
输出结果是:
9997
结果为什么不是10000?10000个线程都执行一遍num++;按理说结果应该是10000。现在的结果却总是小于
等于10000。这就要从++操作的非原子性讲起。想象在某个时刻,两个线程同时读出num值等于30,同时又在自己的工作内存做了++操作,之后先后把
31重新写回主存。这样结果就小于10000了。顺便说一句,这种情况即使加了volatile关键字,也解决不了问题。有volatile也照样覆盖,
因为volatile只能保证读时是最新的。但他解决不了原子问题。像刚才这样,该覆盖时照样覆盖。那怎么解决呢?只有通过原子操作。
import java.util.concurrent.atomic.AtomicInteger;
class MulThreMarkToWin extends Thread {
private AtomicInteger inc;
public void increase() {
inc.getAndIncrement();
}
public MulThreMarkToWin(AtomicInteger inc) {
this.inc = inc;
}
public void run() {
increase();
}
}
public class TestMark_to_win {
public static void main(String[] args){
AtomicInteger inc = new AtomicInteger();
MulThreMarkToWin[] threads = new MulThreMarkToWin[10000];
for (int i = 0; i < 10000;i++) {
threads[i] = new MulThreMarkToWin(inc);
}
for (int i = 0; i < 10000;i++) {
threads[i].start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(inc);
}
}
输出结果是:
当两个线程循环依赖于一对同步对象(monitor)时将发生死锁。马克-to-win例如:
一个线程进入对象ObjA上的监视器,而另一个线程进入对象ObjB上的监视器。如果ObjA中的线程试图调用ObjB上的任何 synchronized
方法,同时,反向的情况也发生,就将发生死锁。
死锁很少发生,但一旦发生就很难调试。
在以下例子中:a正在等待b释放,b也正在等待a释放,a怎么才能释放锁呢?只有a往前移动一个语句,执行完disp,a就能自动释放锁,但执行disp需要b释放锁,所以因为执行不了disp,所以a不能释放锁。b也一样,所以大家就在这互相等,从而发生了死锁。
对
于下面的例子:马克-to-wind1.start()作为一个线程,获得d1的锁。为什么?因为synchronized public void
run().所以run()的synchronized不能去掉。d2.start()作为一个线程获得d2的锁。没有问题,所以打印出来两个“in
ru”。然后,在d1's run()的
d.disp()使得d1试图从d2获得一个锁,因为在这一刻,d.disp()意味着d1.d.disp()=
d2.disp(),意味着d1试图得到一个锁从d2,反之亦然。
如果任何synchronized 删除,不会发生死锁,但安全性降低。
例1.10.1-本章源码
class DeadLockExam extends Thread {
DeadLockExam d;
synchronized void disp() {
System.out.println("in di");
}
synchronized public void run() {
System.out.println("in ru");
try {
Thread.sleep(1000);
} catch (Exception e) {
}
d.disp();
}
}
public class TestMark_to_win {
public static void main(String[] args) {
DeadLockExam d1 = new DeadLockExam();
DeadLockExam d2 = new DeadLockExam();
d1.d = d2;
d2.d = d1;
d1.start();
d2.start();
}
}
运行结果是
in ru
in ru
11.wait()、notify()和notifyAll()方法 (视频下载) (全部书籍)
新手不必过认真研究,有兴趣的可研究这三个方法仅在 synchronized 方法中才能被调用。
wait()方法告知被调用的线程退出监视器马克-to-win并进入等待状态,直到其他线程进入相同的监视器并调用 notify( ) 方法。
notify( ) 方法通知同一对象上某一个调用 wait( )线程。 If any threads are waiting on this
object, one of them is chosen to be awakened. The choice is arbitrary
and occurs at the discretion of the implementation.
notifyAll() 方法通知调用 wait() 的所有线程,竞争胜利的线程将先运行。 The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object。
结论:notifyall是竞争,而notify是由具体实施的jvm决定的。
见下例:
例1.11.1-本章源码
运行结果是
需要等一会,暂时无饭12.一个高层线程工具类(Timer) (视频下载) (全部书籍)
Timer 是一个线程工具。它方便线程来调度任务马克-to-win在后台执行。可能会安排任务为一次性执行,或定期重复执行,下面给出例子:
例1.12.1-本章源码
import java.util.Timer;
import java.util.TimerTask;
class TimExample {
Timer timer;
public TimExample(int seconds) {
timer = new Timer();
/*
public void schedule(TimerTask task,long delay) Schedules the specified
task for execution after the specified delay.安排执行指定的任务在指定延迟后
*/
timer.schedule(new CTask(), seconds * 1000);
}
// Inner class
class CTask extends TimerTask {
/*
* public abstract void run() The action to be performed by this timer
* task.被这个定时器所做的行为
*/
public void run() {
System.out.println("时间到!");
}
}
}
public class TestMark_to_win {
public static void main(String args[]) {
new TimExample(3);
System.out.println("here");
}
}
运行结果是
here
时间到!
例:1.5.1-本章源码
class MyThreadMark_to_win extends Thread{输出结果:
i = 0例:1.5.1_1-本章源码
class MyThreadMark_to_win extends Thread{
private boolean stop;
public void run() {
for (int i = 0; i < 100; i++) {
if (stop) {
System.out.println("退出了");
throw new ArithmeticException("divide by 0");
}
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("i = " + i);
}
}
public void setStop(boolean stop) {
this.stop = stop;
}
}
public class Test {
public static void main(String[] args) {
MyThreadMark_to_win mt = new MyThreadMark_to_win();
mt.start();
try {
Thread.sleep(300);
} catch (Exception e) {
}
mt.setStop(true);
}
}
输出结果:
i = 0
Exception in thread "Thread-0" java.lang.ArithmeticException: divide by 0
at MyThreadMark_to_win.run(Test.java:7)
i = 1
退出了
例:1.5.2-本章源码
class ThreadMark_to_win extends Thread {输出结果:
i = 0例:1.5.2_1-本章源码
class ThreadMark_to_win extends Thread {
Thread mainT;
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("我是子线程,被打断");
return;
}
mainT.interrupt();
}
public void setMainThread(Thread t1) {
mainT = t1;
}
}
public class Test {
public static void main(String[] args) {
Thread mainT = Thread.currentThread();
ThreadMark_to_win st = new ThreadMark_to_win();
st.setMainThread(mainT);
st.start();
try {
Thread.sleep(250);
} catch (InterruptedException e) {
System.out.println("我是主线程,被打断");
}
}
}
例:1.5.2_2-本章源码
class ThreadMark_to_win extends Thread {例:1.5.3-本章源码
class ThreadMark_to_win extends Thread {
int e;
public void run() {
for (int i = 0; i < 4; i++) {
e = e + i;
}
System.out.println("完成");
}
}
public class Test {
public static void main(String[] args) {
ThreadMark_to_win tm = new ThreadMark_to_win();
tm.start();
try {
tm.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("e = " + tm.e);
}
}
输出结果:
完成
e = 6
例:1.5.3_1-本章源码
class ThreadMark_to_win extends Thread {例:1.6.1-本章源码
class ThreadMark_to_win extends Thread {
static boolean go=true;
private String s;
int i;
public ThreadMark_to_win(String s) {
this.s = s;
}
public void run() {
while(go){
System.out.println(s+" 到了 "+i++);
try {
this.sleep(1); // 减小这里的毫秒数,可以让我们更容易观察到结果
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
public class Test {
public static void main(String[] args) {
Thread t1 = new ThreadMark_to_win("线程1");
Thread t2 = new ThreadMark_to_win("线程2");
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadMark_to_win.go=false;
}
}
输出结果:
线程1 到了 0
线程2 到了 0
线程1 到了 1
线程2 到了 1
线程2 到了 2
线程1 到了 2
线程2 到了 3
线程1 到了 3
线程2 到了 4
线程1 到了 4
线程2 到了 5
线程1 到了 5
线程2 到了 6
线程1 到了 6
。
。
。
。
。
。
。
线程1 到了 3335
线程2 到了 4753
线程2 到了 4754
线程2 到了 4755
线程2 到了 4756
线程1 到了 3336
线程2 到了 4757
线程2 到了 4758
线程2 到了 4759
例:1.7.1_1-本章源码
class ThreadMark_to_win extends Thread {
public void run(){
for(int i = 1; i <= 15;i++){
try{
Thread.sleep(100);
} catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println("子线程 "+i);
}
}
}
public class Test extends Thread{
public static void main(String [] args){
ThreadMark_to_win tm = new ThreadMark_to_win();
tm.setDaemon(true);
tm.start();
System.out.println("子线程是精灵线程吗?" +tm.isDaemon());
try{
Thread.sleep(1000);
} catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"已经结束");
}
}
输出结果:
子线程是精灵线程吗?true
子线程 1
子线程 2
子线程 3
子线程 4
子线程 5
子线程 6
子线程 7
子线程 8
子线程 9
main已经结束
子线程 10
例:1.7.1_2-本章源码
class ThreadMark_to_win extends Thread {
public void run(){
for(int i = 1; i <= 15;i++){
try{
Thread.sleep(100);
} catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println("子线程 "+i);
}
}
}
public class Test extends Thread{
public static void main(String [] args){
ThreadMark_to_win tm = new ThreadMark_to_win();
// tm.setDaemon(true);
tm.start();
System.out.println("子线程是精灵线程吗?" +tm.isDaemon());
try{
Thread.sleep(1000);
} catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"已经结束");
}
}
class Photoshop {
private Photoshop() {
}
private static Photoshop photoshop = null;// 这个值独立于任何对象存在,实例化任何对象之前,这个成员就有可能有值。
public static Photoshop getInstanceQixy() {
if (photoshop == null) {
photoshop = new Photoshop();
}
return photoshop;
}
}
public class Test {
public static void main(String[] args) {
Photoshop photoshopI1 = Photoshop.getInstanceQixy();
Photoshop photoshopI2 = Photoshop.getInstanceQixy();
System.out.println(photoshopI1+" "+photoshopI2);
}
}
例:1.8.1_b-本章源码
class Photoshop {
private Photoshop() {
}
private static Photoshop photoshop = null;
public static Photoshop getInstanceQixy() {
if (photoshop == null) {
photoshop = new Photoshop();
}
return photoshop;
}
}
class MyThreadMark_to_win extends Thread {
public void run() {
Photoshop photoshopI1 = Photoshop.getInstanceQixy();
System.out.println(Thread.currentThread().getName() + "实例是 "
+ photoshopI1);
}
}
public class Test {
public static void main(String[] args) {
MyThreadMark_to_win mt1 = new MyThreadMark_to_win();
MyThreadMark_to_win mt2 = new MyThreadMark_to_win();
mt1.start();
mt2.start();
}
}
例:1.8.2-本章源码
class BookMark_to_win {输出结果:
main before10
main after 9
main before9
main after 8
main before8
main after 7
main before7
main after 6
main before6
main after 5
main before5
main after 4
main before4
main after 3
main before3
main after 2
main before2
main after 1
main before1
main after 0
class BookMark_to_win {
int bookNum=10;
void onlySellOne() {
if (bookNum > 0) {
System.out.println(Thread.currentThread().getName()
+ " before" + bookNum);
bookNum--;
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName()
+ " after " + bookNum);
}
}
}
class MyThread extends Thread {
BookMark_to_win book;
MyThread(BookMark_to_win tmp) {
this.book = tmp;
}
public void run() {
while (book.bookNum>0) {
book.onlySellOne();
}
}
}
public class Test {
public static void main(String[] args) {
BookMark_to_win bookM = new BookMark_to_win();
Thread t1 = new MyThread(bookM);
Thread t2 = new MyThread(bookM);
t1.start();
t2.start();
}
}
输出结果:
Thread-0 before10
Thread-1 before9
Thread-0 after 8
Thread-0 before8
Thread-1 after 7
Thread-1 before7
Thread-0 after 6
Thread-0 before6
Thread-1 after 5
Thread-1 before5
Thread-0 after 4
Thread-0 before4
Thread-1 after 3
Thread-1 before3
Thread-0 after 2
Thread-0 before2
Thread-1 after 1
Thread-1 before1
Thread-0 after 0
Thread-1 after 0
例:1.8.2_c-本章源码
class BookMark_to_win {
void onlySellOne() {
int bookNum=10;
while (bookNum > 0) {
System.out.println(Thread.currentThread().getName()
+ " before" + bookNum);
bookNum--;
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName()
+ " after " + bookNum);
}
}
}
class MyThread extends Thread {
BookMark_to_win book;
MyThread(BookMark_to_win tmp) {
this.book = tmp;
}
public void run() {
book.onlySellOne();
}
}
public class Test {
public static void main(String[] args) {
BookMark_to_win bookM = new BookMark_to_win();
Thread t1 = new MyThread(bookM);
Thread t2 = new MyThread(bookM);
t1.start();
t2.start();
}
}
输出结果:
Thread-0 before10
Thread-1 before10
Thread-0 after 9
Thread-0 before9
Thread-1 after 9
Thread-1 before9
Thread-0 after 8
Thread-0 before8
Thread-1 after 8
Thread-1 before8
Thread-0 after 7
Thread-0 before7
Thread-1 after 7
Thread-1 before7
Thread-0 after 6
Thread-0 before6
Thread-1 after 6
Thread-1 before6
Thread-0 after 5
Thread-0 before5
Thread-1 after 5
Thread-1 before5
Thread-0 after 4
Thread-0 before4
Thread-1 after 4
Thread-1 before4
Thread-0 after 3
Thread-0 before3
Thread-1 after 3
Thread-1 before3
Thread-0 after 2
Thread-0 before2
Thread-1 after 2
Thread-1 before2
Thread-0 after 1
Thread-0 before1
Thread-1 after 1
Thread-1 before1
Thread-0 after 0
Thread-1 after 0
例:1.8.2_d-本章源码
class BookMark_to_win {
int bookNum=10;
void onlySellOne() {
if (bookNum > 0) {
System.out.println(Thread.currentThread().getName()
+ " before" + bookNum);
bookNum--;
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName()
+ " after " + bookNum);
}
}
}
class MyThread extends Thread {
BookMark_to_win book;
MyThread(BookMark_to_win tmp) {
this.book = tmp;
}
public void run() {
while (book.bookNum>0) {
book.onlySellOne();
}
}
}
public class Test {
public static void main(String[] args) {
BookMark_to_win bookM = new BookMark_to_win();
BookMark_to_win bookM2 = new BookMark_to_win();
Thread t1 = new MyThread(bookM);
Thread t2 = new MyThread(bookM2);
t1.start();
t2.start();
}
}
输出结果:
Thread-0 before10
Thread-1 before10
Thread-1 after 9
Thread-0 after 9
Thread-0 before9
Thread-1 before9
Thread-1 after 8
Thread-1 before8
Thread-0 after 8
Thread-0 before8
Thread-1 after 7
Thread-1 before7
Thread-0 after 7
Thread-0 before7
Thread-1 after 6
Thread-1 before6
Thread-0 after 6
Thread-0 before6
Thread-0 after 5
Thread-0 before5
Thread-1 after 5
Thread-1 before5
Thread-1 after 4
Thread-1 before4
Thread-0 after 4
Thread-0 before4
Thread-1 after 3
Thread-1 before3
Thread-0 after 3
Thread-0 before3
Thread-0 after 2
Thread-0 before2
Thread-1 after 2
Thread-1 before2
Thread-0 after 1
Thread-0 before1
Thread-1 after 1
Thread-1 before1
Thread-1 after 0
Thread-0 after 0
例1.9.1-本章源码
class Photoshop {
private Photoshop() {
}
private static Photoshop photoshop = null;
public synchronized static Photoshop getInstanceQixy() {
if (photoshop == null) {
photoshop = new Photoshop();
}
return photoshop;
}
}
class MyThreadMark_to_win extends Thread {
public void run() {
Photoshop photoshopI1 = Photoshop.getInstanceQixy();
System.out.println(Thread.currentThread().getName() + "实例是 "
+ photoshopI1);
}
}
public class Test {
public static void main(String[] args) {
MyThreadMark_to_win mt1 = new MyThreadMark_to_win();
MyThreadMark_to_win mt2 = new MyThreadMark_to_win();
mt1.start();
mt2.start();
}
}
输出结果:
Thread-1实例是 Photoshop@a62fc3
Thread-0实例是 Photoshop@a62fc3
class BookMark_to_win {
int bookNum=10;
synchronized void onlySellOne() {
if (bookNum > 0) {
System.out.println(Thread.currentThread().getName()
+ " before" + bookNum);
bookNum--;
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName()
+ " after " + bookNum);
}
}
}
class MyThread extends Thread {
BookMark_to_win book;
MyThread(BookMark_to_win tmp) {
this.book = tmp;
}
public void run() {
while (book.bookNum>0) {
book.onlySellOne();
}
}
}
public class Test {
public static void main(String[] args) {
BookMark_to_win bookM = new BookMark_to_win();
Thread t1 = new MyThread(bookM);
Thread t2 = new MyThread(bookM);
t1.start();
t2.start();
}
}
输出结果:
Thread-0 before10
Thread-0 after 9
Thread-0 before9
Thread-0 after 8
Thread-0 before8
Thread-0 after 7
Thread-0 before7
Thread-0 after 6
Thread-1 before6
Thread-1 after 5
Thread-1 before5
Thread-1 after 4
Thread-0 before4
Thread-0 after 3
Thread-0 before3
Thread-0 after 2
Thread-0 before2
Thread-0 after 1
Thread-0 before1
Thread-0 after 0
class A {
public synchronized void f1() {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println("i = " + i);
}
}
}
class MyThread extends Thread {
A a;
public MyThread(A a) {
this.a = a;
}
public void run() {
a.f1();
}
}
public class TestMark_to_win {
public static void main(String[] args) {
A a = new A();
Thread t1 = new MyThread(a);
Thread t2 = new MyThread(a);
t1.start();
t2.start();
}
}
运行结果是
class A {
public void disp() {
System.out.println("新线程启动:");
for (int i = 0; i < 10; i++) {
System.out.println(i);
try {
Thread.sleep(500);
} catch (Exception e) {
}
}
}
}
public class TestMark_to_win extends Thread {
A a;
public TestMark_to_win(A a) {
this.a = a;
}
public void run() {
a.disp();
}
public static void main(String[] args) {
A a = new A();
TestMark_to_win t1 = new TestMark_to_win(a);
TestMark_to_win t2 = new TestMark_to_win(a);
t1.start();
t2.start();
}
}
例1.9.4_b-本章源码
class A {
public void disp() {
synchronized (this) {
System.out.println("新线程启动:");
for (int i = 0; i < 10; i++) {
System.out.println(i);
try {
Thread.sleep(500);
} catch (Exception e) {
}
}
}
}
}
public class TestMark_to_win extends Thread {
A a;
public TestMark_to_win(A a) {
this.a = a;
}
public void run() {
a.disp();
}
public static void main(String[] args) {
A a = new A();
TestMark_to_win t1 = new TestMark_to_win(a);
TestMark_to_win t2 = new TestMark_to_win(a);
t1.start();
t2.start();
}
}
新线程启动:
0
1
2
3
4
5
6
7
8
9
新线程启动:
0
1
2
3
4
5
6
7
8
9
例1.10.1-本章源码
class DeadLockExam extends Thread {
DeadLockExam d;
synchronized void disp() {
System.out.println("in di");
}
synchronized public void run() {
System.out.println("in ru");
try {
Thread.sleep(1000);
} catch (Exception e) {
}
d.disp();
}
}
public class TestMark_to_win {
public static void main(String[] args) {
DeadLockExam d1 = new DeadLockExam();
DeadLockExam d2 = new DeadLockExam();
d1.d = d2;
d2.d = d1;
d1.start();
d2.start();
}
}
运行结果是
in ru
in ru
例1.12.1-本章源码
import java.util.Timer;
import java.util.TimerTask;
class TimerExample {
Timer timer;
public TimerExample(int seconds) {
timer = new Timer();
timer.schedule(new ConcTask(), seconds * 1000);
}
// Inner class
class ConcTask extends TimerTask {
public void run() {
System.out.println("时间到!");
}
}
}
public class TestMark_to_win {
public static void main(String args[]) {
new TimerExample(5);
System.out.println("here");
}
}
运行结果是
here