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]
xxxxxxxxxx31
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(就是对象锁)可以是任意类型对象
浙公网安备 33010602011771号