黑马程序员--多线程(一)

来源:互联网 发布:关于网络鬼片 编辑:程序博客网 时间:2024/05/24 02:37
------- android培训、java培训、期待与您交流! ----------

1.多线程概述

    进程:就是一个正在执行中的程序,每一个进程执行都有一个顺序,该顺序是一个执行路径或叫一个控制单元.

    线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行,,一个进程中至少有一个线程

    创建线程的方式:继承Thread类或实现Runnable接口

   继承Thread类:1.定义类继承Thread类

                 2.复写Thread类中的run方法

                 3.调用线程的start方法,该方法有两个作用:启动线程,调用run方法

问题:为什么要复写run方法?

答:Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法,也就是说run方法是用来存储线程要运行的代码的

线程状态图


    实现Runnable接口: 1.定义类实现Runnable接口

                      2.覆盖Runnable接口中的run方法

                      3.通过Thread了建立线程对象

                      4.将Runnable接口的子类对象传递给Thread的构造函数

                      5.调用Thread类的start方法开启线程并调用Runnable接口的run方法

问题:为什么要将Runnable接口的子类对象传递给Thread的构造函数?

答:因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去执行指定对象的run方法,就必须明确该run方法所属的对象.

    实现Runnable接口与继承Thread类的区别:继承Thread类线程代码存放于Thread子类run方法中;实现Runnable接口线程代码存在于接口的子类run方法中,而且这种方式避免了单继承的局限性.

2.多线程的安全问题

    当多条语句在操作同一个线程共享数据时,一个线程只执行了一部分,还没有执行完,另一个线程就参与了进来,造成了共享数据的错误,这就是数据安全问题.

    解决办法:对于执行语句,使用同步代码块使得让一个线程执行完,其他线程才能执行,在执行的过程中,其他线程不可以参与.

    同步代码块格式:synchronized(对象){需要被同步的代码;}

    同步的前提:必须要有两个或两个以上的线程;必须是多个线程使用同一把锁

    同步的优点:解决了多线程的安全问题,缺点:多个线程需要判断锁,较为消耗资源

卖票实例:火车站有四个窗口同时出售100张票

class Ticket implements Runnable {private int ticket = 100;public void run() {while (true) {// 同步代码块,一个线程执行不完,另一个就不能执行synchronized (this) {if (ticket > 0)System.out.println(Thread.currentThread().getName()+ "  出售第  " + ticket--);}}}}class TicketDemo {public static void main(String[] args) {Ticket t = new Ticket();Thread t1 = new Thread(t);// 创建了四个线程,传递的参数是Runnable接口的子类对象Thread t2 = new Thread(t);Thread t3 = new Thread(t);Thread t4 = new Thread(t);t2.start();t3.start();t4.start();t1.start();}}

银行实例:模拟银行存钱,账户余额是0,每次存储100元,开启2个银行窗口,每个窗口存3次,存完之后,账户余额是600元.模拟这个过程

//银行类,存钱的方法class Bank{static int sum = 0;//统计余额变量//银行的存钱的功能public static void add(int money){synchronized(Bank.class){    sum = sum + money;System.out.println("sum="+sum);}}}//储户类,调用银行的存钱功能class Custom implements Runnable{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) {Custom cus = new Custom();Thread t1 = new Thread(cus);//建立两个线程表示两个窗口Thread t2 = new Thread(cus);t1.start();t2.start();}}

注意:静态函数的锁不能使用this,需要用类的字节码文件对象

3.死锁

    原理:A线程持有A锁,B线程持有B锁,让A线程去抢夺B锁,B线程去抢夺A锁

class Dead implements Runnable{private boolean b = false;Dead(boolean b){  this.b = b;}public void run(){  while(true)  {     if(b)   {      synchronized(Locks.locka)   {//0线程,持有了A锁     System.out.println(Thread.currentThread().getName()+"  locka...+.. if");     //等待B锁 synchronized(Locks.lockb)   {   System.out.println(Thread.currentThread().getName()+"  lockb...+.. if");   }   }   }   else   {      synchronized(Locks.lockb)   {//1线程就进来了,持有了B锁   System.out.println(Thread.currentThread().getName()+"  lockb...+.. else");          synchronized(Locks.locka)//等待获得A锁   { System.out.println(Thread.currentThread().getName()+"  locka...+.. else");   }   }   }  }}}//创造锁class Locks{public static Object locka = new Object();public static Object lockb = new Object();}class DeadLock {public static void main(String[] args) {Dead d1 = new Dead(true);Dead d2 = new Dead(false);Thread t1 = new Thread(d1);Thread t2 = new Thread(d2);t1.start();t2.start();}}

4.单例模式的懒汉式同步改进

class Single{private static  Single s = null;public static Single getInstance(){if(s==null){   synchronized(Single.class){     if(s==null)  {  try{Thread.sleep(100);}catch(Exception e){}      s = new Single();      } }}return s;}}class SingleThread implements Runnable{public void run(){    for(int x =0 ; x< 20 ; x++){      Single s = Single.getInstance();  System.out.println(s);    }}}class SingleTest {public static void main(String[] args) {SingleThread s =  new SingleThread();        Thread t1 = new Thread(s);        Thread t2 = new Thread(s);        Thread t3 = new Thread(s);        Thread t4 = new Thread(s);t1.start();t2.start();t3.start();t4.start();}}

学习感悟

    创建多线程的方式包括继承Thread类和实现Runnable接口,相比之下实现实现Runnable更优,因为它避免了单继承的局限性.例如,子类需要继承父类,如果使用继承Thread的方式来创建多线程很明显是不可能的,Java类不支持多继承.但子类可以在继承父类的同时实现Runnable接口.多线程加了同步锁以后,同一个代码块只有一个线程在执行,限制了其他线程的进入,避免了线程安全问题.

原创粉丝点击