JAVA入门到精通-第40讲-线程
把思想转换成程序。
线程对象只能启动一个线程;
导入导出项目:
1,copy
2,装到磁盘
3,导入:import---General---Existing Project into Workspace
4,浏览Brose-Copy project into workspace
把项目拷贝到Eclipse中,
不选的话,直接操作;
-----------------------------------------
这是可以的;
这会报错,一个线程类只会启动一次;
数据的并发;
//售票窗口类
//定义三个售票窗口
//控制出票速度:
Thread.sleep(100);
各卖各的票没有共享;
//看哪个线程在卖票
Thread.currentThread().getName()
得到当前线程的名字;
//线程共享所有的票
(1)改成静态的;
(2)用一个窗口,启动三次;
这个数据应该是被共享的;
同一张票被多个线程卖出,没有规律;并发造成的;
a线程执行完1以后没有来得及执行第2句话,b线程进入;
synchronized(Object);
Object称为对象锁;Object类比门;
线程排队-线程等待池-blocked
直到对象锁被打开; 同步代码块; this 就是对象锁,代表对象本身;
有对象锁,线程的并发已经被控制住,会按照顺序卖;
---------------------------
对象锁有0和1标志位,默认1,门打开,进入代码块使用;
在进入的时候,会把标志位,变为0,门被锁上;
如果1进入,1会被放到等待池里排队;
如果2进入,2会先看等待池,有,在等待池排队;
0号执行完,离开,把标志位重置为1,否则,会死锁:
死锁:线程互读,并且并发;
------------------------------------------
线程--区别
线程--继承Thread VS 实现Runnable的区别
从java的设计来看,通过继承Thread或者实现Runnable接口来创建线程本质上没有区别,从jdk帮助文档我们可以看到Thread类本身就实现了Runnable接口,如果一定要说它们有什么区别,总结几点:
1、尽可能使用实现Runnable接口的方式来创建线程
2、在使用Thread的时候只需要new一个实例出来,调用start()方法即可以启动一个线程,如: Thread test=new Thread();
test.start();
3、在使用Runnable的时候需要先new一个实现Runnable的实例,之后用Thread调用,如:
Test implements Runnable
Test t=new Test();
Thread test=new Thread(t);
tset.start();
线程--深入理解
线程对象只能启动一个线程,见[Thread04.java]
xxxxxxxxxx
31
1
/**
2
* 功能:使用线程的注意事项
3
* 不论继承Thread或实现Rnunable接口都不能使用start启同一个线程2次
4
*/
5
public class Thread04 {
6
public static void main(String[] args) {
7
Cat cat1=new Cat();
8
cat1.start();
9
//cat1.start();同一个线程,不能启动2次
10
11
Dog dog1=new Dog();
12
Thread t=new Thread(dog1);
13
t.start();
14
//t.start();同一个线程,不能启动2次
15
}
16
}
17
18
//猫类
19
class Cat extends Thread{
20
public void run(){
21
System.out.println("11");
22
}
23
}
24
25
//狗类
26
class Dog implements Runnable{
27
public void run(){
28
System.out.println("2");
29
}
30
}
31
---------------------------------------------------------
结论:不管是通过继承Thread,还是通过实现Runnable接口创建线程,它们的一个对象只能启动(即:start())一次。否则就会有异常抛出。
两种创建线程的方法的区别
创建线程有两种方法:1、继承Thread;2、实现Runnable接口;
这两种方法有什么区别?
用实现Runnable接口的特点
1、用实现Runnable接口的方法创建对象可以避免java单继承机制带来的局限;
2、用实现Runnable接口的方法,可以实现多个线程共享同一段代码(数据);
因此建议大家如果你的程序有同步逻辑需求,则使用Runnable的方法来创建线程。
java线程的同步--提出问题
多线程的并发,给我们编程带来很多好处,完成更多更有效率的程序。但是也给我们带来线程安全问题。
java线程的同步--解决问题
解决问题的关键就是要保证容易出问题的代码的原子性,所谓原子性就是指:当a线程在执行某段代码的时候,别的线程必须等到a线程执行完后,它才能执行这段代码。也就是排队一个一个解决。
java处理线程两步的方法非常简单,只需要在需要同步的代码段,用:
synchronized(Object){你要同步的代码}
即可。
售票案例演示[Thread05.java]
1
/**
2
* 功能:使用线程的注意事项
3
* 线程并发同步锁synchronized(Object){}的使用
4
*/
5
public class Thread05 {
6
public static void main(String[] args) {
7
//定义一个售票窗口
8
TicketWindow tw1=new TicketWindow();
9
10
//使用三个线程同时启动
11
Thread t1=new Thread(tw1);
12
Thread t2=new Thread(tw1);
13
Thread t3=new Thread(tw1);
14
15
t1.start();
16
t2.start();
17
t3.start();
18
}
19
}
20
21
//售票窗口类
22
class TicketWindow implements Runnable {
23
//共有2000张票
24
private int nums=2000;
25
private Dog myDog=new Dog();
26
27
public void run() {
28
while(true){
29
//出票速度是1秒出一张
30
try {
31
Thread.sleep(1000);
32
} catch (Exception e) {
33
e.printStackTrace();
34
}
35
36
//认为if else要保证其原子性
37
//先判断是否还有票
38
synchronized(myDog){//synchronized(this){}为同步代码块
39
if(nums>0){
40
//显示售票信息
41
//Thread.currentThread().getName()得到当前线程的名字
42
System.out.println(Thread.currentThread().getName()+"正在售出第"+nums+"张票");
43
nums--;
44
}else{
45
//售票结束
46
break;
47
}
48
}
49
}
50
}
51
}
52
53
class Dog{
54
}
55
------------------------------------
java线程的同步--解决问题
对同步机制的解释:
java任意类型的对象都有一个标志位,该标志位具有0、1两种状态,其开始状态为1,当某个线程执行了synchronized(Object)语句后,object对象的标志位变为0的状态,直到执行完整个synchronized语句中的代码块后,该对象的标志位又回到1状态。
当一个线程执行到synchronized(Object)语句的时候,先检查Object对象的标志位,如果为0状态,表明已经有另外的线程正在执行synchronized包括的代码,那么这个线程将暂时阻塞,让出CPU资源,直到另外的线程执行完相关的同步代码,并将Object对象的标志位变为状态,这个线程的阻塞就被取消,线程能继续运行,该线程又将Object的标志位变为0状态,防止其它的线程再进入相关的同步代码块中。
如果有多个线程因等待同一个对象的标志位面而处于阻塞状态时,当该对象的标志位恢复到1状态时,只会有一个线程能够进入同步代码执行,其它的线程仍处于阻塞的状态。
特别说明:
1、上面所说的标志位用术语讲就是对象锁,文件锁。数据库会有行锁、表锁等
2、synchronized(object)//object(就是对象锁)可以是任意类型对象