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(就是对象锁)可以是任意类型对象

  
 

 




猜你喜欢

转载自www.cnblogs.com/xuxaut-558/p/10045751.html