<span style="background-color: rgb(255, 255, 255); font-family: Arial; font-size: 14px; line-height: 26px;"></span><pre name="code" class="plain">
</pre>
<pre name="code" class="sql">
-------
Android培训
、
java培训
、期待与您交流! ----------
</pre>
/* 多线程:
*
* 进程:
* 是一个正在执行中的程序,每一个进程执行都有一个执行的顺序。该顺序是一个执行路径或者叫一个控制单元
* CPU不断切换对进程进行执行
*
* 线程:
* 线程就是进程中一个独立的控制单元,线程在控制着进程的执行
* 一个进程中至少有一个线程
*
* 多线程存在的意义
* 线程的创建方式
* 多线程的特性
*/
/*
* Java虚拟机启动的时候会有一个进程java.exe
* 该进程中至少有一个线程在负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为
* 主线程。
*/
class ThreadDemo
{
public static void main(String[] args)
{
for(int x=0;x<4000;x++)
System.out.println("hello world!");
}
}
/*
* 启动时观察windows任务管理器发现:
* 编译时javac.exe进程启动了,编译完又消失了
* 运行时java.exe进程启动了,运行完也消失了
*
* 说明了java有两个进程:编译进程、运行进程
*
* 扩展:其实更细节说明虚拟机,虚拟机启动不止一个线程,除了主线程还有负责垃圾回收机制的线程
*
* 多线程的存在有什么意义呢?
* 多线程可以让程序中的部分产生同时运行的效果,多线程的下载可以提高下载的效率
*
*/
/*
如何在自定义的代码中去自定义一个线程呢?
创建新执行线程有两种方法:
1、创建线程的第一种方式:继承Thread类
通过对API的查找,java已经提供了对线程这类事物的描述,就是Thread类
Thread:线程。是程序中的执行线程。
步骤:
(1)、定义类继承Thread
(2)、复写Thread类中的run方法
目的:将自定义代码存储在run方法中,让线程运行
(3)、调用线程的start方法,start:使该线程开始执行,Java虚拟机调用该线程的run方法
该方法有两个作用:a.启动线程 b.调用run方法
2、创建线程的第二种方式:实现Runnable接口
步骤:
(1)、定义类实现Runnable
(2)、覆盖Runnable接口中的run方法,将线程要运行的代码存放在run方法中
(3)、通过Thread类建立线程对象
(4)、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
为什么要将Runnable接口的子类对象传递给Thread的构造函数?
因为,自定义的run方法所属的对象是Runnable接口的子类对象
所以要让对象去执行指定对象的run方法。就必须明确该run方法所属的对象
(5)、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
一般鼓励使用第二种方法,因为Java里面只允许单一继承,但允许实现多个接口。第二个方法更加灵活。
*/
class Demo1 extends Thread
{
public void run()//run是用来封装线程要运行的代码
{
System.out.println("demo run");
}
}
class ThreadDemo1
{
public static void main(String[] args)
{
Demo1 d=new Demo1();//创建好一个线程
d.start();//开启线程,并执行该线程的run方法
}
}
/*
* 运行结果为:
* demo run
*/
/*
* 以下程序是一个多线程程序。两个for循环会交替执行,此时CPU在切换执行。所以双核CPU运行速度快
*
* 多线程程序: main
* ↓
* Demo2 d=new Demo2();
* d.start();——————┐
* ↓ ↓
* hello world demo run
* 打印结果是交替打印的
*/
class Demo2 extends Thread
{
public void run()
{
for(int x=0;x<40;x++)
System.out.println("demo run"+x);
}
}
class ThreadDemo2
{
public static void main(String[] args)
{
Demo2 d=new Demo2();
//d.run();//仅仅是对象调用方法,而线程Demo1 d=new Demo1();创建了却并没有运行,执行完run
//再执行下面的程序
d.start();//开启线程并执行该线程的run方法,
for(int x=0;x<60;x++)
System.out.println("hello world"+x);
}
}
/*
* 以上程序发现运行结果每一次都不同
* 因为多个线程都获取CPU的执行权,CPU执行到谁,谁就运行
* 明确一点,在某一个时刻,只能有一个程序在运行(多核除外)
* CPU在做着快速的切换,以达到看上去是同时运行的效果
* 我们可以形象的把多线程的运行行为看成是在互相抢夺CPU的执行权
*
* 这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长时间,CPU说的算
*
* 为什么要覆盖run方法呢?
* Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法
* 也就是说Thread类中的run方法,用于存储线程要运行的代码。
*
class ThreadDemo extends Thread
{
public static void main(String[] args)
{
Thread t=new Thread();
t.start();
}
}
以上这种调用没意义
*/
/*
练习:
创建两个线程,和主线程交替运行
*/
class Test3 extends Thread
{
public void run()
{
for(int x=0;x<40;x++)
{
System.out.println(" run....."+x);
}
}
}
class ThreadTest3
{
public static void main(String[] args)
{
Test3 t1=new Test3();
Test3 t2=new Test3();
t1.start();//开启第一个线程
t2.start();//开启第二个线程
for(int x=0;x<60;x++)
System.out.println("main....."+x);
}
}
/*
* 运行结果发现两个线程都在交替运行,但区分不出分别是哪个线程运行的。
*
* 所以为了区分出2个线程的执行情况,给两个线程分别起一个名字
*/
class Test extends Thread
{
private String name;
Test(String name)
{
this.name=name;
}
public void run()
{
for(int x=0;x<40;x++)
{
System.out.println(name+" run....."+x);
}
}
}
class ThreadTest
{
public static void main(String[] args)
{
Test t1=new Test("one");//创建第一个线程,为了使这个线程清晰,传一个"one"
Test t2=new Test("two");//创建第二个线程,为了使这个线程清晰,传一个"two"
t1.start();//开启第一个线程
t2.start();//开启第二个线程
for(int x=0;x<60;x++)
System.out.println("main....."+x);
}
}
/*
* 以上程序开启线程将start换成用run方法,就会执行完"one run....x"再执行"two run....x",
* 最后执行"main....."就不会交替执行了
*/
/*
* 创建线程方式一:
* 继承Thread类
* 1、子类覆盖父类中的run方法,将线程运行的代码存放在run中
* 2、建立子类对象的同时,线程也被创建
* 3、通过调用start方法开启线程
*
*
* 原来线程都有自己默认的名称,"Thread-编号",该编号从0开始,获取方法:getName()
*/
class Test1 extends Thread
{
public void run()
{
for(int x=0;x<40;x++)
{
System.out.println(this.getName()+" run...."+x);
}
}
}
class ThreadTest1
{
public static void main(String[] args)
{
Test1 t1=new Test1();//即使加入自定义名称显示的还是默认名称Thread—编号
Test1 t2=new Test1();//即使加入自定义名称显示的还是默认名称Thread—编号
t1.start();
t2.start();
for(int x=0;x<60;x++)
System.out.println("main....."+x);
}
}
/*
* 以上两个线程执行的是默认名称Thread-编号,我们如何才能让线程显示自己定义的名称"one"和"two"呢?
* Thread类中有Thread(String name)方法,可以直接继承父类Thread类的这个方法就可以显示自定义名称了。
*
* static Thread currentThread:获取当前线程对象
* 设置线程名称:setName 或者 构造函数
*/
class Test2 extends Thread
{
Test2(String name)
{
super(name);//继承Thread类中定义名称的方法
}
public void run()
{
for(int x=0;x<40;x++)
{
/*Thread.currentThread()==this,写哪一个都可以
*其中"Thread.currentThread()"表示运行Thread类中的currentThread()线程*/
System.out.println(this.getName()+" run....."+x);
}
}
}
class ThreadTest2
{
public static void main(String[] args)
{
Test2 t1=new Test2("one");
Test2 t2=new Test2("two");
t1.start();
t2.start();
for(int x=0;x<60;x++)
System.out.println("main....."+x);
}
}
/*
* 以上程序两个线程执行run方法中的for循环,所执行的x是不是一个x?
* 不是!两个线程在进入run方法中的for循环时,内存会给两个线程分别开辟2个内存空间,每个空间都有一个
* run方法,每个run方法中都有一个x
*/
/*
* 需求:简单的卖票程序
* 多个窗口同时卖票
*/
class Ticket extends Thread
{
private static int tick=100;//这儿如果不加static就会每个线程都出现卖100张票的情况
public void run()
{
/*
* 如果单看while中的条件:true.这段程序应该是一个无限循环,但当while循环里中有return x,
* 那么当程序执行到return的时候,就回自动跳出循环,并返回x.
*/
while(true)
{
if(tick>0)
{
System.out.println(this.getName()+"...sale:"+tick--);
}
/*
* break的作用简单说就是跳出当前的整个循环,下面有个简单说明:
* break语句可以强迫程序中断循环,当程序执行到break语句时,即会离开循环,继续执行
* 循环外的下一个语句,如果break语句出现在嵌套循环中的内层循环,则break语句只会跳出
* 当前层的循环;
*/
else
break;
}
}
}
class TicketDemo
{
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();
}
}
/*
* 虽然将票数定义成静态可以,但是一般不建议用静态,因为生命周期过长,那该如何写呢?
* 可以将以上代码运用“创建线程的方式二”来创建
*
* 创建线程的第二种方式:实现Runnable接口
* 步骤:
* 1、定义类实现Runnable接口
*
* 2、覆盖Runnable接口中的run方法
* 将线程要运行的代码存放在该run方法中
*
* 3、通过Thread类建立线程对象
*
* 4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
* 为什么要将Runnable接口的子类对象传递给Thread的构造函数?
* 因为,自定义的run方法所属的对象是Runnable接口的子类对象
* 所以要让对象去执行指定对象的run方法。就必须明确该run方法所属的对象
*
* 5、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
*
* 实现方式和继承方式有什么区别呢?(经常会考的面试题!)
*
* 实现方式好处:避免了单继承的局限性,例:如果Student类是Person的子类,他就不能再继承Thread类。
* 如果用Runnable接口就比较方便
* 在定义线程时,建议使用实现方式,这种方法是最常用的。但如果建立的类没有自己的父类用继承也可以
*
* 两种方式的区别:
* 继承Thread类:线程代码存放在Thread子类run方法中
* 实现Runnable:线程代码存放在Runnable接口子类的run方法中
*/
class Ticket1 implements Runnable
{
private int tick=100;//共享数据
public void run()
{
while(true)
{
if(tick>0)//线程执行的多条语句
{
System.out.println(Thread.currentThread().getName()+"...sale:"+tick--);
}
else
break;
}
}
}
class TicketDemo1
{
public static void main(String[] args)
{
Ticket1 t=new Ticket1();//这个对象不是线程,因为它和Thread类没关系
//方法:Thread(Runnable target)表示能接收一个Runnable接口类型的对象
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();
}
}
//但以上程序卖票系统会出现安全问题,打印出了0、-1、-2等错票
class Ticket2 implements Runnable
{
private int tick=100;//线程共享数据
public void run()
{
while(true)
{
if(tick>0)//线程执行的多条语句
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"...sale:"+tick--);
}
else
break;
}
}
}
class TicketDemo2
{
public static void main(String[] args)
{
Ticket2 t=new Ticket2();//这个不是线程
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();
}
}
/*
* 以上程序通过分析发现,打印出了0,-1,-2等错票
* 多线程的运行出现了安全问题
*
* 问题的原因:
* 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完
* 另一个线程参与进来执行,导致了共享数据的错误
*
* 解决办法:
* 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中其他线程不可以参与执行
*
* JAVA对于多线程的安全问题提供了专业的解决方式,就是同步代码块
* synchronized(对象)
* {
* 需要被同步的代码
* }
* 哪些代码需要被同步,就看哪些语句需要操作共享数据。即不能同时有多个线程执行
*
* 对象如同锁,持有锁的线程可以在同步中执行。没有持有锁的线程,即使获取了CPU的执行权也进不去,
* 因为没有获取锁。火车上的卫生间——经典!
*
* 同步的前提:
* 1、必须要有两个或两个以上的线程
* 2、必须是多个线程使用同一个锁
*
* 必须保证同步中只能有一个线程在运行
*
* 好处:解决了多线程的安全问题
* 弊端:多个线程都需要判断锁,较为消耗资源
*/
class Ticket3 implements Runnable
{
private int tick=100;
Object obj=new Object();//创建一个对象
public void run()
{
while(true)
{
synchronized(obj)//这个对象“obj”相当于锁,叫同步锁。它有两个标志位0和1,起判断线程
//的作用
{
if(tick>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"...sale:"+tick--);
}
else
break;
}
}
}
}
class TicketDemo3
{
public static void main(String[] args)
{
Ticket3 t=new Ticket3();//这个不是线程
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、明确哪些代码是多线程运行代码
* 答:run方法中的都是,add方法也是
*
* 2、明确共享数据
* 答:b和sum
*
* 3、明确多线程运行代码中,哪些语句是操作共享数据的
* 答:b.add(100);是操作共享数据的,但它只有一句话,您能分开读
* sum=sum+n;System.out.println("sum="+sum);这两句也是操作共享数据的,
* 所以是这两句
*/
class Bank
{
private int sum=0;
public void add(int n)
{
sum=sum+n;
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 BankDemo
{
public static void main(String[] args)
{
Cus c=new Cus();
Thread t1=new Thread(c);
Thread t2=new Thread(c);
t1.start();
t2.start();
}
}
/*
运行结果为:
sum=100
sum=200
sum=300
sum=400
sum=500
sum=600
*/
//这个程序经过以下检查发现存在安全问题:
class Bank1
{
private int sum;
public void add(int n)
{
sum=sum+n;
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println("sum="+sum);
}
}
class Cus1 implements Runnable
{
private Bank1 b=new Bank1();
public void run()
{
for(int x=0;x<3;x++)
{
b.add(100);
}
}
}
class BankDemo1
{
public static void main(String[] args)
{
Cus1 c=new Cus1();
Thread t1=new Thread(c);
Thread t2=new Thread(c);
t1.start();
t2.start();
}
}
/*
运行结果为:
sum=400
sum=400
sum=600
sum=600
*/
//以上安全隐患,可以加入同步代码块来解决
class Bank2
{
private int sum;
Object obj=new Object();
public void add(int n)
{
synchronized(obj)//同步代码块
{
sum=sum+n;
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println("sum="+sum);
}
}
}
class Cus2 implements Runnable
{
private Bank2 b=new Bank2();
public void run()
{
for(int x=0;x<3;x++)
{
b.add(100);
}
}
}
class BankDemo2
{
public static void main(String[] args)
{
Cus2 c=new Cus2();
Thread t1=new Thread(c);
Thread t2=new Thread(c);
t1.start();
t2.start();
}
}
/*
运行结果为:
sum=100
sum=200
sum=300
sum=400
sum=500
sum=600
*/
//也可以写为以下同步函数的形式:
class Bank4
{
private int sum;
public synchronized void add(int n)//也可以写为同步函数
{
sum=sum+n;
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println("sum="+sum);
}
}
class Cus4 implements Runnable
{
private Bank4 b=new Bank4();
public void run()
{
for(int x=0;x<3;x++)
{
b.add(100);
}
}
}
class BankDemo4
{
public static void main(String[] args)
{
Cus4 c=new Cus4();
Thread t1=new Thread(c);
Thread t2=new Thread(c);
t1.start();
t2.start();
}
}
//卖票程序也可以改为同步函数的形式
class Ticket4 implements Runnable
{
private int tick=100;
public synchronized void run()//同步函数,但是这样只有一个进程进去循环,这个线程进去把所有票都打印完了
//也没出来
{
while(true)
{
if(tick>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"...sale:"+tick--);
}
}
}
}
class TicketDemo4
{
public static void main(String[] args)
{
Ticket4 t=new Ticket4();
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();
}
}
//以上写法只有一个线程执行了打印票的操作,他都打印完了其他线程也没执行,所以仍是错的,可以写为:
class Ticket5 implements Runnable
{
private int tick=100;
public void run()
{
while(true)
{
this.show();
}
}
public synchronized void show()
{
if(tick>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"...sale:"+tick--);
}
}
}
class TicketDemo5
{
public static void main(String[] args)
{
Ticket5 t=new Ticket5();
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();
}
}
/*
* 同步函数用的是哪一个锁呢?
* 函数需要被对象调用,那么函数都有一个所属对象引用,就是this
* 所以同步函数使用的锁是this
*
* 通过该函数进行验证
* 为了验证使用两个线程来卖票
* 一个线程在同步代码块中,一个线程在同步函数中,都在执行卖票动作
*/
class Ticket6 implements Runnable
{
private int tick=100;
Object obj=new Object();
boolean flag=true;
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 TicketDemo6
{
public static void main(String[] args)//这个程序一共有3个线程:主线程、t1、t2
{
Ticket6 t=new Ticket6();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
/*
* 主线程执行时这个不一定执行,有执行资格但主线程才有执行权,所以可能没等执行它就先执行完了
* 下面的语句。解决办法是主程序到t1.start();时先停一下
*/
t1.start();
t.flag=false;
t2.start();
}
}
//以上程序把主线程执行完才执行了其他线程,所以要让程序停一下,改为:
class Ticket8 implements Runnable
{
private int tick=100;
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 TicketDemo8
{
public static void main(String[] args)
{
Ticket8 t=new Ticket8();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
t.flag=false;
t2.start();
}
}
/*
* 以上代码运行时还是出现了安全问题,出现了0票,说明同步的2个前提中至少有一个不满足:
* 1、必须要有两个或两个以上的线程
* 2、必须是多个线程使用同一个锁
* 两个中的一个,不满足哪一个呢?
* 第一个条件符合,有两个线程,那么就是不满足第二个使用同一个锁,同步代码块的锁是"obj",同步函数的锁是"this"。
* 所以将同步代码块的锁是"obj"换为"this"即可:
*/
class Ticket11 implements Runnable
{
private int tick=100;
boolean flag=true;
//Object obj=new Object();
public void run()
{
if(flag)
{
while(true)
{
synchronized(this)//将同步代码块的锁也改为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 TicketDemo11
{
public static void main(String[] args)
{
Ticket11 t=new Ticket11();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
t.flag=false;
t2.start();
}
}
/*
* 如果同步函数被静态修饰后,使用的锁是什么呢?
* 通过验证发现又出现了0张票,说明锁不再是this了,因为静态方法中也不可以定义this
*/
class Ticket9 implements Runnable
{
private static int tick=100;
boolean flag=true;
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 static synchronized void show()
{
if(tick>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"...show....:"+tick--);
}
}
}
class TicketDemo9
{
public static void main(String[] args)
{
Ticket9 t=new Ticket9();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
t.flag=false;
t2.start();
}
}
/*
* 静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象:类名.class 该对象的类型是
* Class
*
* 静态的同步方法,使用的锁是该方法所在类的字节码文件对象。也就是:类名.class
*/
class Ticket10 implements Runnable
{
private static int tick=100;
boolean flag=true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(Ticket10.class)//这里的锁改为"类名.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 TicketDemo10
{
public static void main(String[] args)
{
Ticket10 t=new Ticket10();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
t.flag=false;
t2.start();
}
}
/*
* 单例设计模式:
*
* 饿汉式
* class Single
* {
* private Single()
* {
*
* }
* //加上final表示s终身指向new Single()这个对象,更为严谨
* private static final Single s=new Single();
*
*
* public static Single getInstance()
* {
* return s;
* }
* }
*
*
*/
//懒汉式
class Single
{
//下面这句不能加上final,因为s不能终身为null,否则赋值就赋不了了
private static Single s=null;
private Single(){}
public static Single getInstance()
{
if(s==null)
s=new Single();
return s;
}
}
//如果加入同步代码块可以解决安全问题。但加入同步代码块虽然解决了安全问题但每次都要判断锁比较低效
class Single7
{
private Single7(){}
private static Single7 s=null;
public static synchronized Single7 getInstance()//加入synchronized
{
if(s==null)
s=new Single7();
return s;
}
}
class SingleDemo7
{
public static void main(String[] args)
{
Single7 v=Single7.getInstance();
}
}
//如何做既能解决安全问题又能使程序高效?
class Single8
{
private Single8(){}
private static Single8 s=null;
public static Single8 getInstance()
{
//③其它线程又进来执行到这儿s不为空了,所以不再执行了
if(s==null)
{
//①线程A、B同时进来了,但进入同步代码块的只能有一个,假设A进到代码块里了,B留在外面了
//——>B
synchronized(Single8.class)
{
//②A进来后判断s是否为空,是的,所以A往下执行
if(s==null)
//——>A,A进入后创建了本类对象
s=new Single8();
}
}
return s;
}
}
class SingleDemo8
{
public static void main(String[] args)
{
Single8 v=Single8.getInstance();
}
}
/*
* 面试可能会出的问题:
* 1、懒汉式和饿汉式有什么不同?
* 答:懒汉式的特点在于延迟加载
*
* 2、懒汉式的延迟加载有没有问题?怎么解决?
* 答:有。如果多线程访问时会出现安全问题
* 可以加同步来解决。用同步代码块或同步函数都行,但是有些低效。用双重判断的形式能解决效率问题
*
* 3、懒汉式加同步时使用的的锁是哪一个?
* 答:该类所属的字节码文件对象
*
* 以上代码要会写,多写几遍。要求面试的时候如果是笔试题能写出来就行。
* 让写一个延迟加载的单例设计模式时就写以上懒汉式代码即可
*
*
*/
/*
* 死锁:
* 同步中嵌套同步,而锁却不同
class Ticket12 implements Runnable
{
private static int tick=100;
Object obj=new Object();
boolean flag=true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(obj)//Object锁里有this锁
{
show();
}
}
}
else
while(true)
show();
}
public static synchronized void show()//this锁里有Object锁
{
synchronized(obj)
{
if(tick>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"...code:"+tick--);
}
}
}
}
class TicketDemo12
{
public static void main(String[] args)
{
Ticket12 t=new Ticket12();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
t.flag=false;
t2.start();
}
}
运行结果没有全部打印出来,运行一会儿没都打印出来就锁住了
*/
//一个死锁程序:
class Test12 implements Runnable
{
private boolean flag;
Test12(boolean flag)
{
this.flag=flag;
}
public void run()
{
if(flag)
{
synchronized(MyLock.Locka)
{
System.out.println("if Locka");
synchronized(MyLock.Lockb)
{
System.out.println("if Lockb");
}
}
}
else
{
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 DeadLockTest
{
public static void main(String[] args)
{
Thread t1=new Thread(new Test12(true));
Thread t2=new Thread(new Test12(false));
t1.start();
t2.start();
}
}
/*
* 运行结果为:
* else lockb
* if locka
* 死锁了,只打印这两个。多运行几次有可能会出现4个语句全部打印的情况
*
* 面试题有可能会出让你写一个死锁程序
*/