43-

33 阅读9分钟
### 并行和并发
并行: 同一时刻,多个程序同时执行
并发: 同一时间段,多个程序交替执行
1.分时调度:
	为每个线程分配相同的执行时间
2.抢占式调度:
	CPU优先执行优先级别高的线程,多个相同优先级的线程,CPU就随机选择一个执行
### 主线程----------至少有一个线程,用于执行main方法中的代码,称为主线程/main线程   
## 线程的创建Thread1.定义类继承Thread2.Thread类的子类覆盖重写run方法
 3.创建Thread类的子类对象
 4.Thread类的子类对象调用start方法,开启线程
 1.开启线程必须调用start方法,不能直接调用run方法
            如果调用run方法没有多线程的执行效果   
  2.多线程程序运行结果具有随机性
  获取线程名称:
	1.Thread类的成员方法
       getName(): 返回该线程的名称。  setName(String name): 设置该线程的名称。
       public Thread(String name): 通过构造方法指定线程名称 
	2.如何获取main线程的名称呢? 静态方法   static Thread currentThread(): 返回对当前正在执行的线程对象,此方法currentThread在哪个线程中执行,获取到的就是那个线程对象
        3静态方法:  static   sleep(long millis): 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
        第一种
     //Thread的子类
public class SubThread03 extends Thread {
    public SubThread03(String name) {
        super(name);
    }
    @Override
    public void run() {
        //获取线程名称
        //String threadName = super.getName();
        String threadName = Thread.currentThread().getName();
        for (int i = 0; i < 10; i++) {
            System.out.println(threadName+"..."+i);
        }
    }
}
//测试类
public class Demo03Thread {
    public static void main(String[] args) {
        /*SubThread03 t1 = new SubThread03();
        SubThread03 t2 = new SubThread03();
        SubThread03 t3 = new SubThread03();

        //修改线程名称
        t1.setName("张三");
        t2.setName("李四");
        t3.setName("王五");*/

        SubThread03 t1 = new SubThread03("zs");
        SubThread03 t2 = new SubThread03("ls");
        SubThread03 t3 = new SubThread03("ww");

        t1.start();
        t2.start();
        t3.start();
        //因为currentThread方法是在main线程中执行
        //返回的main线程对象
        Thread mainThread = Thread.currentThread();
        System.out.println("--------------------------main线程名称: "+mainThread.getName());
    }
}   
//测试类
public class Demo04Sleep {
    public static void main(String[] args) throws InterruptedException {
        //模拟发射火箭
        for (int i = 10; i >= 1; i--) {
            Thread.sleep(1000);
            System.out.println(i);
        }
        System.out.println("发射....");
    }
}
第二钟
    1.定义实现类,实现Runnable接口new Thread(task);
    2.实现类覆盖重写Runnable接口抽象方法run 
    3.创建Runnable接口的实现类对象
    4.创建Thread线程对象,构造方法传递Runnable接口的实现类对象
    5.Thread线程对象调用start方法,开启线程
  好处   1.避免extend thread java类的单继承的局限性
    2.降低了线程对象和线程任务对象的耦合性
        耦合性: 事物与事物之间的关系
        高内聚,低耦合
    3.可以实现多个线程共享一个任务
    //定义Runnalbe接口实现类
public class MyRunnable04 implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName()+"....."+i);
        }
    }
}
//测试类
public class Demo05Thread {
    public static void main(String[] args) {
        //3.创建Runnable接口的实现类对象        
        MyRunnable04 task = new MyRunnable04();

        //4.创建Thread线程对象,构造方法传递Runnable接口的实现类对象       
        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        Thread t3 = new Thread(task);

        //5.Thread线程对象调用start方法,开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}
//测试类
public class Demo06Thread {
    public static void main(String[] args) {
        //3.创建Runnable接口的实现类对象
        //只是创建线程任务对象,不是线程对象(没有继承Thread类)
        MyRunnable04 task = new MyRunnable04();

        //4.创建Thread线程对象,构造方法传递Runnable接口的实现类对象
        //只是创建一个线程对象,需要执行什么任务,通过构造方法传递过来
        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        Thread t3 = new Thread(task);

        //5.Thread线程对象调用start方法,开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}
第三种匿名内部类方式创建线程
   作用: 创建子类/实现类对象的快捷方式
    格式:
        new 抽象父类/接口(){
            覆盖重写所有的抽象方法
        }

	含义: 	1.该对象没有名字 2.该对象所属的类没有名字
			(底层: JVM根据抽象类/接口,帮助我们创建一个子类/实现类,并生成构造方法)
                        
public class Demo05Thread {
    public static void main(String[] args) {
        //1.匿名内部类方式创建线程: 单独创建创建Runnable接口的实现类对象和线程对象
        //多态创建Runnable接口的实现类对象
        Runnable task1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("线程任务A...");
            }
        };

        //创建线程对象,传递Runnable接口的实现类对象
        Thread t1 = new Thread(task1);

        //线程对象调用start方法开启线程
        t1.start();

        //2.匿名内部类方式创建线程: 单独创建Thread对象,传递Runnable接口的实现类对象

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程任务B...");
            }
        });

        t2.start();

        //3.匿名内部类方式创建线程: 直接创建Thread对象并开启线程,传递Runnable接口的实现类对象

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程任务C...");
            }
        }).start(); 
    }
}

##使用同步代码块方式解决多线程操作共享数据问题 3个线程共同销售100张电影票

使用同步技术 保证操作共享数据的多条语句,要么全部执行,要么全部都不执  
同步代码块 格式:
    	synchronized(任意对象) {
        	...
    	}
        
	2.注意:
    	(1)所有操作共享数据的代码必须写在{}中
    	(2)任意对象: 锁对象/对象锁,专业术语对象监视器
    	(3)锁对象可以是任意对象,但是必须要保证唯一
同步方法    格式: 修饰符 synchronized 返回值类型 方法名称(参数列表...){
        方法体代码
    }     
     (1)所有操作共享数据的代码必须写在{}中
    (2)同步方法不能自己指定锁对象
    (3)非静态同步方法而言:  锁对象,必须有: this 
    静态同步方法内部锁对象: 静态方法所在类的Class对象MySellTicketTask03.class
//创建Runnable接口的实现类
public class MySellTicketTask02 implements Runnable {
    //多个线程共享的数据
    private int num = 100; 
    //锁对象可以是任意对象,但是必须要保证唯一
    //因为MySellTicketTask02的对象只有一个
    //成员lock只有一份,保证了唯一
    private Object lock = new Object();

    @Override
    public void run() {
        //int num = 100;//100张票被三个线程共享使用
        //死循环
        while(true) {

            //同步代码块
            //synchronized (new Object()) {//Object对象作为锁对象,会出现3个
            //synchronized (lock) {
            synchronized (this) {//this代表调用run方法的对象task,而task只有一个
                //(1)判断是否有票
                if (num > 0) {
                    //(2)有票: 打印输出一张票
                    //模拟出票的时间
                    try {Thread.sleep(100);}catch (Exception e){e.printStackTrace();}
                    String threadName = Thread.currentThread().getName();
                    System.out.println(threadName+"卖出第 "+num+" 张票...........");

                    //(3)票的数量减少1张
                    num--;
                }

            }
        }
    }
}
//测试类
public class Demo02Tickets {
    public static void main(String[] args) {
        //3.创建Runnable接口的实现类的对象,线程任务对象
        MySellTicketTask02 task = new MySellTicketTask02();

        //4.创建3个线程对象,构造方法发传递线程任务对象
        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        Thread t3 = new Thread(task);

        //5.这3个线程对象分别调用start方法,开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}
        

同步方法

//创建Runnable接口的实现类
public class MySellTicketTask03 implements Runnable {
    //多个线程共享的数据
    private int num = 100;

    //锁对象可以是任意对象,但是必须要保证唯一
    //因为MySellTicketTask02的对象只有一个
    //成员lock只有一份,保证了唯一
    private Object lock = new Object();

    @Override
    public void run() {
        //int num = 100;//100张票被三个线程共享使用
        //死循环
        while(true) {
            //调用sellA方法
            //sellA();
            //调用sellB方法
            sellB();
        }
    }

    //定义同步方法sellB,不能指定锁对象
    //使用this作为锁对象
    public synchronized void sellB() {

        //(1)判断是否有票
        if (num > 0) {
            //(2)有票: 打印输出一张票
            //模拟出票的时间
            try {Thread.sleep(100);}catch (Exception e){e.printStackTrace();}
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName+"卖出第 "+num+" 张票...........");

            //(3)票的数量减少1张
            num--;
        }
    }

    //定义普通方法sellA,内部使用同步代码块
    public void sellA() {
        //this代表调用sellA方法的对象,sellA方法是在run方法内部调用的,哪个对象调用run方法,该对象就是调用sellA方法的对象
        //task对象调用run方法,sellA方法也是由task对象
        synchronized (this) {
            //(1)判断是否有票
            if (num > 0) {
                //(2)有票: 打印输出一张票
                //模拟出票的时间
                try {Thread.sleep(10);}catch (Exception e){e.printStackTrace();}
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+"卖出第 "+num+" 张票...........");

                //(3)票的数量减少1张
                num--;
            }

        }
    }
}
//测试类
public class Demo03Tickets {
    public static void main(String[] args) {
        //3.创建Runnable接口的实现类的对象,线程任务对象
        MySellTicketTask03 task = new MySellTicketTask03();


        //4.创建3个线程对象,构造方法发传递线程任务对象
        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        Thread t3 = new Thread(task);

        //5.这3个线程对象分别调用start方法,开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}

##死锁

两个线程(保证只能有2个)就会处于无限的等待中,即死锁。在程序中的死锁将出现在同步代码块的嵌套中。
     若无外力作用,它们都将无法推进下去。
     同步: 同步中嵌套同步
### 死锁对象的定义
/*
    定义锁对象  保证只能有2个
 */
public class MyLock {
    public static final MyLock LOCKA = new MyLock();
    public static final MyLock LOCKB = new MyLock();
    private MyLock(){}//外部无法创建对象
}
/*
    定义线程任务类
 */
public class DeadLockTask implements Runnable{
    //定义布尔变量,目的: 不同的线程执行不同的同步代码块
    private boolean flag;
    //构造方法
    public DeadLockTask(boolean flag) {
        this.flag = flag;
    }
    @Override
    public void run() {
        while(true) {
            if(flag) {
                synchronized (MyLock.LOCKA) {                    System.out.println(Thread.currentThread().getName()+"if....lockA.....");
                    synchronized (MyLock.LOCKB) {                        System.out.println(Thread.currentThread().getName()+"if....lockB.....");
                    }
                }
            } else {
                /*try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
                synchronized (MyLock.LOCKB) {                    System.out.println(Thread.currentThread().getName()+"else....lockB.....");
                    synchronized (MyLock.LOCKA) {                        System.out.println(Thread.currentThread().getName()+"else....lockA.....");
                    }
                }
            }
        }
    }
}
//测试类
/*
    死锁案例演示
    死锁是指两个或两个以上的线程在执行过程中,由于竞争同步锁而产生的一种阻塞的现象,
        若无外力作用,它们都将无法推进下去。
 */
public class Demo04DeadLock {
    public static void main(String[] args) {
        //创建线程任务对象
        DeadLockTask taskA = new DeadLockTask(false);
        DeadLockTask taskB = new DeadLockTask(true);
        //创建线程对象,传递线程任务对象
        Thread threadA = new Thread(taskA);
        Thread threadB = new Thread(taskB);
        //开启线程 调用start方法开启线程,指定线程名称
        threadA.start();
        threadB.start();
    }
}