-------android培训、java培训、期待与您交流! ----------
1.多线程概述
(1)进程:一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是
一个执行路径,或叫一个控制单元。
(2)线程:进程序中的一个独立的控制单元,线程控制着进程的执行。一个进程至少有一个线程。
(3)JVM启动时有一个进程java.exe,该进程至少有一个线程负责java程序的执行,这个线程运行的
代码存在于main方法中,该线程叫主线程。
(4)JVM启动时,还有一个负责垃圾回心机制的线程。
(5)多线程的特点:随机性。(谁抢到资源,谁就执行。)
(6)多线程的好处:
可使程序中的部分产生同时运行的效果,多线程下载可提高效率。
2.创建线程方式一:继承Thread类
(1)Thread是描述线程的类。
(2)创建步骤:
<1>定义类继承Thread.
<2>复写Thread类中的run方法(目的:将自定义代码存储在run方法,让线程运行)
<3>调用线程的start方法。(该方法作用:启动线程,调用run方法)
注:start():开启并执行该线程的run方法。
run():仅仅是对象调用方法,而线程创建了并不运行。
3.线程的五种状态
(1)被创建:
(2)运行:
(3)阻塞(临时状态):具备执行资格,但没有执行权。
(4)冻结:放弃了执行资格。
(5)消亡:
注:建立线程子类对象的同时线程也被创建。
4.获取线程对象以及名称
(1)线程都有自己默认的名称:Thread-编号(从0开始)
(2)Thread的几个方法:
static Thread currentThread():获取当前线程对象。
getName():获取线程名称。
setName()或构造函数:设置线程名称。
5.创建线程方式二:实现Runnable接口
(1)步骤:
定义类实现Runnable接口。
覆盖Runnable接口中的run方法,
通过Thread类建立线程对象。
将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
调用Thread类的start立法开启线程并调用Runnable接口子类的run方法。
(2)实现方式和继承方式的区别:
继承了一个类就不能再继承其他类,java只支持单继承。继承的同时还可以实现接口。
(3)实现方式的好处:
避免了单继承的局限性,在定义线程时,建议使用实现方式。
(4)两种方式的区别:
继承Thread:线程代码存放Thread子类的run方法中。
实现Runnable:线程代码存放在接口的子类的run方法中。
6.线程安全
(1)原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,
还没有执行完,另一个线程参与进来执行,导致共享数据的错误。
(2)解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以
参与执行,java提供的专业解决方式就是同步代码块。
synchronized(对象)
{
需要被同步的代码;
}
(3)同步代码块
<1>对象如同锁,持有锁的线程才可以在同步中执行。
<2>举例说明:火车上的卫生间。
<3>同步的前提:
必须要有两个或两个以上的线程。
必须是多个线程使用同一个锁。
<4>必须保证同步中只能有一个线程在运行。
<5>好处:解决了多线程的安全问题。
缺点:多个线程需要判断锁,比较消耗资源。
(4)同步函数
<1>同步有两种表现形式:同步代码块和同步函数。
<2>举例:
需求:
银行有一个金库,有两个储户分别存300元,每次存100,存3次。
(5)同步函数的锁:this
函数需要被对象调用,那么函数都有一个所属对象引用就是this,所以同步函数使用的锁是this.
(6)静态同步函数的锁:class对象
<1>因为静态方法中不可以定义this,所以锁不可能是this。静态进内存时,内存中没有本类对象,
但是一定有该类对应的字节码文件对象,类名.class,该对象的类型是class.
<2>静态的同步方法使用的锁是该方法所在类的字节码文件对象。类名.class.
(7)死锁:同步中钳套同步。
7.线程间通信
(1)线程间通信:
其实就是多个线程在操作同一个资源,但操作的动作不同。
(2)等待唤醒机制:
<1>wait(),notify(),notifyAll()都使用在同步中,因为只有同步才具有锁,所以要对持有锁的
线程操作。
<2>这些用来操作线程的方法为什么定义在Object类中?
a.这些方法存在于同步中。
b.使用这些方法时必须要标识所属的同步的锁。
c.等待和唤醒必须是同一个锁。
d.锁可以是任意对象,所以任意对象调用的方法一定定义在Object中。
(3)wait(),sleep()的区别:
wait():释放资源,释放锁。
sleep():释放资源,不释放锁。
(3)举例:生产者与消费者
<1>对于多个生产者和消费者,为让被唤醒的线程再一次判断标记,故要定义while判断标记。
<2>为什么定义notifyAll?
因为需要唤醒对方线程,只用notify容易出现只唤醒本方线程的情况,导致程序中的所有
线程都等待。
<3>JDK1.5提供的多线程升级解决方案。
将同步synchronized替换成现实Lock操作。将Object中的wait,notify,notifyAll替换成了
condition对象。该对象可以用Lock锁进行获取。
8.停止线程:
(1)stop方法已经过时。
(2)如何停止线程?
只有一种,就是让run方法结束,开启多线程运行,运行代码通常是循环结构。只要控制住循环,
就可以让run方法结束,也就是线程结束。
(3)特殊情况:
<1>当线程处于了冻结状态,就不会读到标记,那么线程就不会结束。
<2>当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除,强制让线程恢复
到运行状态中来,这样就可以操作标记让线程结束。
(4)Thread类提供该方法:interrupt()
9.守护线程:
setDaemon:
public final void setDaemon(boolean on)
(1)当正在运行的线程都是守护线程时,JVM退出。
(2)该方法必须在启动线程前调用。
(3)主线程是前台线程,前台线程一结束,守护线程自动结束。
10.join方法:
join://抢夺CPU执行权
public final void join()
throws InterruptedException
等待该线程终止
(1)当A线程执行到了B线程的join()方法时,A就会等待,等B线程都执行完,A才会执行。
(2)join可以用来临时加入线程执行。
11.优先级&yield方法
setPriority(int newPriority)
更改线程的优先级(默认是5)
(1) MAX_PRIORITY-->10
NORM_PRIORITY--->5
MIN_PRIORITY--->1
(2)注:在任务管理器的进程中,也可进行优先级设置。
yield:临时停止
public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。yield可稍微减缓线程的运行,
使线程达到接近平均运行的效果。
以下我是练习的代码:
/* 1 ,
class Demo extends Thread{
public void run(){
System.out.println("Demo run()");
}
}
class ThreadDemo01{
public static void main(String args[]){
Demo d = new Demo();
d.start();
}
}
*/
/*
class Demo extends Thread{
public void run(){
for(int x = 0;x<60;x++)
System.out.println("Demo run()***"+x);
}
}
class ThreadDemo01{
public static void main(String args[]){
Demo d = new Demo();
d.start();
for(int x = 0;x<60;x++)
System.out.println("Hello world!---"+x);
}
}
*/
//创建两个线程,和主线程交替运行。
/*
class Test extends Thread{
private String name; //创建子类特有属性
Test(String name){
this.name = name;
}
public void run(){
for(int x =0;x<60;x++){
System.out.println(name+"...run ...."+x); //调用子类特有的属性
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one"); //带参数的构造方法实例化对象。
Test t2 = new Test("two");
t1.run();
t2.run();
//t1.start();
//t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
//9 ,线程都有自己默认的名称:Thread-编号,该编号从0开始。
//如调用this.getName()方法。这个方法为父类的方法,子类没覆写,输出的是父类默认的线程名称。
class Test extends Thread{
private String name;
Test(String name){
this.name = name;
}
public void run(){
for(int x =0;x<60;x++){
System.out.println(name+"...run ...."+x);
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one");
Test t2 = new Test("two");
t1.run();
t2.run();
//t1.start();
//t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
//没有建立子类的特有属性,而是子类覆写父类的构造方法,通过调用this.getName(),返回自定义的线程名称。
class Test extends Thread{
//private String name;
Test(String name){
//this.name = name;
super(name);
}
public void run(){
for(int x =0;x<60;x++){
System.out.println(this.getName()+"...run ...."+x);
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one");
Test t2 = new Test("two");
t1.run();
t2.run();
//t1.start();
//t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
//这样就有了自定义的名称了。
class Test extends Thread{
//private String name;
Test(String name){
//this.name = name;
super(name);
}
public void run(){
for(int x =0;x<60;x++){
System.out.println(this.getName()+"...run ...."+x);
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one");
Test t2 = new Test("two");
//t1.run();
//t2.run();
t1.start();
t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
//这样可调用getName方法,返回的是子类自定义的线程名称
//因为子类覆写了父类中的name属性。
class Test extends Thread{
private String name;
Test(String name){
//this.name = name;
super(name);
}
public void run(){
for(int x =0;x<60;x++){
System.out.println(this.getName()+"...run ...."+x);
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one");
Test t2 = new Test("two");
//t1.run();
t2.run();
//t1.start();
//t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
//这样做也能自定义名称。只是访问时,不能用name来访问,因为,这是访问子类的特有属性,而这个属性只进行了默认初始化,而
//没有进行自定义赋值。
//因为子类对象中name属性没赋值,而是把子类构造中传入的参数直接赋给
//父类中的name属性了,run方法中name属性是子类特有的
//而非父类的,通过super.name访问父类属性报错,父类该属性为私有的。可通过this.getName()方式访问
//可采用如下题方式。
class Test extends Thread{
private String name ; //类中的成员变量会默认进行初始化,而局部变量不会。
Test(String name){
//this.name = name;
super(name);
}
public void run(){
for(int x =0;x<60;x++){
System.out.println(name+"...run ...."+x);
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one");
Test t2 = new Test("two");
//t1.run();
//t2.run();
//t1.start();
t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
//此种方式可以,因为子类调用了自己的特有内容,而非调用父类中的内容。,但这种方式费力,因为父类中已定义好了一个这样的方法
//我们直接覆写就行了。
class Test extends Thread{
private String name; //类中的成员变量会默认进行初始化,而局部变量不会。
Test(String name){
this.name = name;
//super(name);
}
public void run(){
for(int x =0;x<60;x++){
System.out.println(name+"...run ...."+x);
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one");
Test t2 = new Test("two");
//t1.run();
//t2.run();
//t1.start();
t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
// 验证子父类中的构造方法。
class ThreadDemo02{
private String name = "wwww";
//创建子类对象时,默认先调用父类中无参的构造方法
public ThreadDemo02(){}
public ThreadDemo02(String name){
this.name = name;
}
}
class ThreadDemo01 extends ThreadDemo02{
//private String name="rrrr";
public ThreadDemo01(String name){
//this.name = name;
super(name);
}
public static void main(String args[]){
ThreadDemo01 t = new ThreadDemo01("wfy");
System.out.println(t.name);
}
}
*/
/*
//此种方式和下一种有何区别?
class Test extends Thread{
private String name; //类中的成员变量会默认进行初始化,而局部变量不会。
Test(String name){
this.name = name;
//super(name);
}
public void run(){
for(int x =0;x<60;x++){
//该方法为父类中的方法,得到的是父类线程名称,如果子类有参数的构造方法覆写了父类中的有参数构造方法,调用的是子类自定义
//的线程名称,如没覆写而调用此方法,显示的是父类默认的线程名称。
System.out.println(this.getName()+"...run ...."+x);
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one");
Test t2 = new Test("two");
//t1.run();
//t2.run();
//t1.start();
t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
//此种方式和上一种有何区别?
//getName方法访问的是父类中name属性,如果子类覆写了父类中的该属性,调用此法返回的是子类属性内容
//如果子类没覆写父类中此属性,调用后返回的是父类的属性。
//当子类有参数的构造方法覆写父类中带参数的构造方法后,子类调用this.getName()方法返回的是
//子类自定义的名字,而如果没覆写父类中带参数的构造方法而是建立自己特有的
//属性,那么此方法可通过this.name方式来访问,而不能通过this.getName()方法,因为
//该方法在子类没覆写父类带参数的构造方法时默认调用父类中自定义的线程名称,
//而如果子类覆写了此构造方法,则调用子类的名称。
class Test extends Thread{
//private String name; //类中的成员变量会默认进行初始化,而局部变量不会。
Test(String name){
//this.name = name;
super(name);
}
public void run(){
for(int x =0;x<60;x++){
//该方法为父类中的方法,得到的是父类自定义的线程名称,而非子类的。
System.out.println(this.getName()+"...run ...."+x);
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one");
Test t2 = new Test("two");
//t1.run();
//t2.run();
//t1.start();
t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
class Test extends Thread{
//private String name;
Test(String name){
//this.name = name;
super(name);
}
public void run(){
for(int x =0;x<60;x++){
//currentThread
System.out.println((currentThread()==this)+"..."+this.getName()+"...run ...."+x);
}
}
}
class ThreadDemo01{
public static void main(String argsp[]){
Test t1 = new Test("one");
Test t2 = new Test("two");
//t1.run();
//t2.run();
//t1.start();
t2.start();
for(int i =0;i<60;i++)
System.out.println("Main ..run ----");
}
}
*/
/*
//需求:简单的卖票程序。多个窗口同时买票。
class Ticket extends Thread{
//静态的用法:生命调用长。
private static int tick = 100;
public void run(){
while(true){
if(tick>0){
System.out.println(currentThread()+"\tsale : "+tick--);
}
}
}
}
class ThreadDemo01{
public static void main(String args[]){
Ticket t1 = new Ticket();
Ticket t2 = new Ticket();
Ticket t3 = new Ticket();
Ticket t4 = new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
*/
/*
//需求:简单的卖票程序。多个窗口同时买票。
//当调用完第一个start()方法后,线程由临界状态进入运行状态,
//如果在次调用start()方法,已无意义。illegalthreadstateException;
class Ticket extends Thread{
//静态的用法:生命调用长。
private int tick = 100;
public void run(){
while(true){
if(tick>0){
System.out.println(currentThread()+"\tsale : "+tick--);
}
}
}
}
class ThreadDemo01{
public static void main(String args[]){
Ticket t1 = new Ticket();
//Ticket t2 = new Ticket();
//Ticket t3 = new Ticket();
//Ticket t4 = new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
*/
/*
//需求:简单的卖票程序。多个窗口同时买票。
class Ticket implements Runnable{
//静态的用法:生命调用长。
private int tick = 100;
Object obj = new Object();
public void run(){
while(true){
//此处有异常,只能try不能抛,因为子类覆写父类方法后只能声明抛出
//父类异常的子集,如父类的这个方法没抛异常,子类只能try不能抛。
synchronized(obj){ 此处用谁的锁都可以,但必须保证锁的唯一。
if(tick>0){
try{
Thread.sleep(10);
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"\tsale : "+tick--);
}
}
}
}
}
class Thread02{
public static void main(String args[]){
Ticket t = new Ticket();//此方式不是在创建线程 ,而是建立要运行的代码
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
*/
//需求:银行有一个金库,有两个储户分别存300元,每次存100,存3次。
//该程序是否有安全问题,如果有,如何解决。
//如何找问题:
//1 ,明确哪些代码是多线程运行代码,不是的,不需要同步!!
//2 ,明确共享数据。
//3 ,明确多线程运行代码中哪些语句是操作共享的。
/*
class Bank{
private int sum; //共享数据
Object obj = new Object();
//此处可抛出异常,但在执行b.add(100);时,必须try不能再抛了,
//因为子类Run中不能抛出父类没有的异常。
public void add(int n){
synchronized(obj){
sum = sum +n;
try{Thread.sleep(10);}catch(Exception e){}
System.out.println("sum = "+sum);
}
}
}
class Cus implements Runnable{
private Bank b = new Bank(); //共享数据
public void run(){
for(int x = 0;x<3;x++){
b.add(100); //
}
}
}
class Thread02{
public static void main(String args[]){
Cus c = new Cus();
Thread t1 = new Thread(c);//共享C中的属性
Thread t2 = new Thread(c);//共享C中的属性
t1.start();
t2.start();
}
}
*/
/*
//如果你创建了两个线程,但运行各自的Run方法,那么也没必要用同步代码块!!
//因为各自Run方法中只有一个线程不存在内部竞争(没有安全问题)
//同步代码块使用的前提:①有多个线程②各线程用的是同一个锁。
class Bank{
private int sum; //共享数据
Object obj = new Object();
public void add(int n){
sum = sum +n;
try{Thread.sleep(100);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"存放:"+n+"\t总钱数:"+sum);
}
}
class Cus1 implements Runnable{
private Bank b = new Bank(); //共享数据
public void run(){
for(int x = 0;x<3;x++){
b.add(100); //
}
}
}
class Cus2 implements Runnable{
private Bank b = new Bank(); //共享数据
public void run(){
for(int x = 0;x<3;x++){
b.add(1000); //
}
}
}
class Thread02{
public static void main(String args[]){
Cus1 c1 = new Cus1();
Cus2 c2 = new Cus2();
Thread t1 = new Thread(c1,"A 用户:");//一个储户,存300
Thread t2 = new Thread(c2,"B 用户:");//另一个储户,存300
t1.start();
t2.start();
}
}
*/
/*
//这个里面必须要用同步锁 !!!!!!!!!
//储户的数量由创建的线程的个数来决定
//储存的钱数由各自用户中的Run方法来完成。
//如果你创建了两个线程,但运行各自的Run方法,那么也没必要用同步代码块!!
//因为各自Run方法中只有一个线程不存在内部竞争(没有安全问题)
class Bank{
private int sum; //共享数据
Object obj = new Object();
public void add(int n){
synchronized(Cus.class){
sum = sum +n;
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"存放:"+n+"\t"+Thread.currentThread().getName().substring(0,1)+"家族总钱数:"+sum);
}
}
}
class Cus1 implements Runnable{
private Bank b = new Bank(); //共享数据
public void run(){
for(int x = 0;x<3;x++){
b.add(100); //
}
}
}
class Cus2 implements Runnable{
private Bank b = new Bank(); //共享数据
public void run(){
for(int x = 0;x<3;x++){
b.add(1000); //
}
}
}
class Thread02{
public static void main(String args[]){
Cus1 c1 = new Cus1();
Cus2 c2 = new Cus2();
Thread t1 = new Thread(c1,"A 用户:");//一个储户,存300
Thread t3 = new Thread(c1,"A A 用户:");//一个储户,存300
Thread t2 = new Thread(c2,"B 用户:");//另一个储户,存300
Thread t4 = new Thread(c2,"B B 用户:");//另一个储户,存300
t1.start();
t3.start();
t2.start();
t4.start();
}
}
*/
///
/*
//银行总钱数 多线程的! 单例设计模式!!!!!
class Bank{
double sum = 0;
private static Bank b = new Bank();
public static Bank getInstance(){
return b;
}
}
class Consumer1 implements Runnable{
//private Bank b = new Bank();
Bank b = Bank.getInstance();
private static Consumer1 con1 = new Consumer1();
private Consumer1(){}
public static Consumer1 show(){
return con1;
}
public void add(double d){
synchronized(Bank.class){
b.sum = b.sum+d;
System.out.println(Thread.currentThread().getName()+"存入:"+d+"\t"+"银行总钱数:"+b.sum);
}
}
public void run(){
for(int i =0;i<3;i++)
Consumer1.show().add(100);
}
}
class Consumer2 implements Runnable{
//private Bank b = new Bank();
Bank b = Bank.getInstance();
private static Consumer2 con2 = new Consumer2();
public static Consumer2 show(){
return con2;
}
public void add(double d){
synchronized(Bank.class){
b.sum = b.sum+d;
System.out.println(Thread.currentThread().getName()+"存入:"+d+"\t"+"银行总钱数:"+b.sum);
}
}
public void run(){
for(int i =0;i<3;i++)
Consumer2.show().add(1000);
}
}
class Thread02{
public static void main(String args[]){
Thread t1 = new Thread(Consumer1.show(),"A");
Thread t2 = new Thread(Consumer1.show(),"A");
Thread t3 = new Thread(Consumer2.show(),"B");
Thread t4 = new Thread(Consumer2.show(),"B");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
*/
///
/* //同步函数代码块的使用 同步代码块 和同步函数。
class Bank{
private int sum; //共享数据
Object obj = new Object();
public synchronized void add(int n){
sum = sum +n;
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"存放:"+n+"\t"+Thread.currentThread().getName().substring(0,1)+"家族总钱数:"+sum);
}
}
class Cus1 implements Runnable{
private Bank b = new Bank(); //共享数据
public void run(){
for(int x = 0;x<3;x++){
b.add(100); //
}
}
}
class Cus2 implements Runnable{
private Bank b = new Bank(); //共享数据
public void run(){
for(int x = 0;x<3;x++){
b.add(1000); //
}
}
}
class Thread02{
public static void main(String args[]){
Cus1 c1 = new Cus1();
Cus2 c2 = new Cus2();
Thread t1 = new Thread(c1,"A 用户:");//一个储户,存300
Thread t3 = new Thread(c1,"A A 用户:");//一个储户,存300
Thread t2 = new Thread(c2,"B 用户:");//另一个储户,存300
Thread t4 = new Thread(c2,"B B 用户:");//另一个储户,存300
t1.start();
t3.start();
t2.start();
t4.start();
}
}
*/
/*
//需求:简单的卖票程序。多个窗口同时买票。
class Ticket implements Runnable{
//静态的用法:生命调用长。
private int tick = 1000;
Object obj = new Object();
public synchronized void run(){ //如果在多线程中在Run方法上声明该字,那么程序相当于单线程,因为其它运行该方法
while(true){ //的线程进不来!!!
if(tick>0){
try{
Thread.sleep(10);
}catch(Exception e){}
System.out.println(Thread.currentThread()+"\tsale : "+tick--);
}
}
}
}
class Thread02{
public static void main(String args[]){
Ticket t = new Ticket();//此方式不是在创建线程 ,而是建立要运行的代码
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
*/
/*
//此程序有三个线程,主线程启动后,创建对象,创建两个线程,开启了一个,这个线程不一定立刻执行,
//可能会执行t.flag = flase;所以打印结果不确定。//本程序有问题,因为不是用的同一个锁!!!!!!!!!!
class Ticket implements Runnable{
//静态的用法:生命调用长。
private int tick = 100;
public boolean flag = true;
Object obj = new Object();
public void run(){
if(flag){
while(true){
synchronized(obj){
if(tick>0){
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+".Code----"+tick--);
}
}
}
}else
while(true)
show();
}
public synchronized void show(){
if(tick>0){
try{
Thread.sleep(10);
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"**show ******"+tick--);
}
}
}
class Thread02{
public static void main(String args[]){
Ticket t = new Ticket();//此方式不是在创建线程 ,而是建立要运行的代码
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}//主线程睡眠,让开启的线程运行,,此时只用一个线程可运行!!!
t.flag = false;
t2.start();
}
}
*/
/*
// 由此证明是同一个this.
class Ticket implements Runnable{
//静态的用法:生命调用长。
private int tick = 100;
public boolean flag = true;
//Object obj = new Object();
public void run(){
if(flag){
while(true){
synchronized(this){
if(tick>0){
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"..Code----"+tick--);
}
}
}
}else
while(true)
show();
}
public synchronized void show(){
if(tick>0){
try{
Thread.sleep(10);
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"*******show ******"+tick--);
}
}
}
class Thread02{
public static void main(String args[]){
Ticket t = new Ticket();//此方式不是在创建线程 ,而是建立要运行的代码
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(8);}catch(Exception e){}//主线程睡眠,让开启的线程运行,,此时只用一个线程可运行!!!
t.flag = false;
t2.start();
}
}
*/
/*
//静态同步方法,使用的锁是该方法所在类的字节码文件对象。类名.Class.
class Ticket implements Runnable{
//静态的用法:生命调用长。
static private int tick = 100;
public boolean flag = true;
//Object obj = new Object();
public void run(){
if(flag){
while(true){
synchronized(this){//应改为:Ticket.class
if(tick>0){
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"..Code----"+tick--);
}
}
}
}else
while(true)
show();
}
public static synchronized void show(){
if(tick>0){
try{
Thread.sleep(10);
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"*******show ******"+tick--);
}
}
}
class Thread02{
public static void main(String args[]){
Ticket t = new Ticket();//此方式不是在创建线程 ,而是建立要运行的代码
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(8);}catch(Exception e){}//主线程睡眠,让开启的线程运行,,此时只用一个线程可运行!!!
t.flag = false;
t2.start();
}
}
*/
/*
//饿汉式
class Single{
private static final Single s = new Single();
private Single(){}
public static Single getInstance(){
return s;
}
}
//懒汉式加同步,低效!!
class Single{
private static Single s = null;
private Single(){}
public static synchronized Single getInstance(){
if(s==null)
//-->A
//-->B
s = new Single();//对象被延迟。
return s;
}
}
//写一个延迟加载的单例设计模式 试例
//双重判断提高效率。实例的延迟加载,在多线程访问时,会出现安全问题,
//解决方案,有两种加同步锁函数或同步代码块都行,但稍有低效,但用双重
//判断的方式能解决这个效率问题,加同步时,如使用同步函数使用的锁是本类
//所属的字节码文件对象,它在类的加载时,产生,只加载一次。
class Single{
private static Single s = null;
private Single(){}
public static Single getInstance(){
if(s==null){//
synchronized(Single.class){//只要有一个对象初始化完,其它的都执行不到这里。减少了锁的判断。
if(s==null)
//-->A
//-->B
s = new Single();//对象被延迟。
}
}
return s;
}
}
*/ //重点!!!!!!!!!
//死锁!!!!!!!!
/*
class Ticket implements Runnable{
//静态的用法:生命调用长。
private int tick = 200;
public boolean flag = true;
Object obj = new Object();
public void run(){
if(flag){
while(true){
synchronized(obj){
show();
}
}
}else
while(true)
show();
}
public synchronized void show(){
synchronized(obj){
if(tick>0){
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"..Code----"+tick--);
}
}
}
}
class Thread02{
public static void main(String args[]){
Ticket t = new Ticket();//此方式不是在创建线程 ,而是建立要运行的代码
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(12);}catch(Exception e){}//主线程睡眠,让开启的线程运行,,此时只用一个线程可运行!!!
t.flag = false;
t2.start();
}
}
*/
///
/*
//死锁程序重点掌握!!!只有理解了死锁,写程序时,才会刻意避免它。
class Test implements Runnable{
private boolean flag;
Test(boolean flag){
this.flag = flag;
}
public void run(){
if(this.flag){
while(true){
synchronized(MyLock.locka){
System.out.println("if lockaaaa");
synchronized(MyLock.lockb){
System.out.println("\tif lockbbbbbb");
}
}
}
}else{
while(true){
synchronized(MyLock.lockb){
System.out.println("else lockb");
synchronized(MyLock.locka){
System.out.println("else locka");
}
}
}
}
}
}
class MyLock{
static Object locka = new Object();
static Object lockb = new Object();
}
class Thread02{
public static void main(String args[]){
Thread t1 = new Thread(new Test(true));
Thread t2 = new Thread(new Test(false));
t1.start();
t2 .start();
}
}
*/