多线程基础(一)

来源:互联网 发布:怎么开淘宝店铺 编辑:程序博客网 时间:2024/06/11 18:23

一. 线程与进程

1.进程:是一个正在执行中的程序。 每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者控制单元。
线程:就是一个进程中的一个独立执行的控制单元。
线程控制着进程的执行,一个进程至少有一个线程。
2. 线程的几种状态:
1)创建
new Thread() 以及子类对象
2)运行
3)冻结 sleep wait 没有执行资格
4)消亡 stop()
5)阻塞状态:具备运行资格,但是没有执行权
3. 线程的标识:(详细使用见例2)
1)setName GetName
2)Thread.CurrentThread 静态对象,获取当前线程对象
getName():获取线程名称

二. thread类用于描述线程,有两种方法

1.方法一:继承
步骤:
(1)定义类继承Thread类
(2)重写run方法
目的:将自定义的代码存储在run方法中,让线程运行
(3)在主函数中new一个对象,创建线程
(4)thread.start() 启动并执行线程
结果:.
运行结果每次都不同,原因是每个线程都在抢夺CPU的使用权,
在同一时刻,只能有一个程序运行
原因分析:
1.为什么要覆盖run方法
Thread用于描述线程,该类定义了一个功能用于存储线程要运行的代码,
该存储功能就是run方法。也就是Thread类中的run方法用于存储线程要运行的代码
2.为什么不使用d.run()方法?
d.run() 仅仅是对象调用方法,而线程创建了并没有运行。
//有两个进程在同时执行,一个是主函数的进程Hello World,另外一个是demo run进程
例一

 class Demo extends Thread{                                        public void run(){                                            for(int x=0;x<80;x++)                                            System.out.println("demo run--->"+x);                                        }                                    }                        public class ThreadDemo {                                public static void main(String[] args) {                                // TODO Auto-generated method stub                               Demo d=new Demo();//创建好一个线程                               d.start();                               for(int x=0;x<60;x++){                                   System.out.println("Hello World--->"+x);                               }                            }                        }

例2 设置线程名称

class Test extends Thread{                        private String name;                        Test(String name){                            //this.name=name;                            super(name);                        }                        public void run(){                            for(int i=0;i<60;i++)                            System.out.println(this.getName()+" test run--->"+i);                        }                    }                    public class testRun {                        public static void main(String[] args) {                            // TODO Auto-generated method stub                          Test t1=new Test("one--");                          Test t2=new Test("two++");                          t1.start();                          t2.start();                          for(int x=0;x<60;x++){                              System.out.println(Thread.currentThread().getName()+" main--->"+x);                          }                        }                    }

2.方法二:实现runnable接口
步骤:
1.定义一个类实现runnable接口
2.复写run方法
将线程运行代码存放在该方法中
3.创建类对象
3.创建多个线程
4.线程调用类对象,即将类对象作为参数传递
原因:自定义的run方法所属对象为runable接口的子类对象,
所以要让线程去指定对象的run方法。必须明确run所属对象
5.线程调用start开启线程
对比:
方法一和方法二的区别:
(1) java只支持单继承,一个Ticket继承Thread后,不能继承其他类
实现多个接口,实现方式避免了单继承的局限性,在定义线程时,建议使用接口。
(2) 继承Thread:线程代码存放在Thread的run方法中
实现runnable:线程代码存放在runnable的run方法中

三. 线程同步

同步有两种方式:同步代码块和同步函数。
同步的前提条件:
(1)有两个或者两个以上的线程
(2)必须多个线程使用同一个锁
好处:解决多线程的安全问题
弊端:多个线程都需要判断锁,消耗资源
如何找问题:
(1)明确那些代码是多线程运行代码
(2)明确共享数据
(3)明确多线程运行代码中哪些语句是操作共享数据的
1. 同步代码块中的synchronized的参数必须为一个对象
这时,直接实例化object类
售票的同步代码块:

class Ticket implements Runnable{    private  int tick=100;    Object obj=new Object();    public void run(){        while(true){            synchronized (obj) {                    if(tick>0){                try {                    //不能抛出异常,原因是:run方法复写了父类的run方法,                    //父类没有设置抛出,因而不能抛出异常,只能处理异常                    Thread.sleep(10);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread().getName()+" sale:"+tick--);            }            }        }    }}

售票的同步函数(一)

class Ticket implements Runnable{    private  int tick=100;    Object obj=new Object();    public void run(){        while(true){        this.show();            }        }    public synchronized void show(){        if(tick>0){            try {                //不能抛出异常,原因是:run方法复写了父类的run方法,                //父类没有设置抛出,因而不能抛出异常,只能处理异常                Thread.sleep(10);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName()+" sale:"+tick--);        }    }}

售票的同步函数(二)——静态修饰符

class Ticket implements Runnable{    private static int tick=100;    Object obj=new Object();    public void run(){        while(true){        this.show();            }        }    public static synchronized void show(ticket.class){        if(tick>0){            try {                Thread.sleep(10);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName()+" sale:"+tick--);        }    }}

四. 实例:1,2,3,4个窗口卖出100张票

采用方法一:

class Ticket extends Thread{        private String name;        Ticket(String name){            super(name);        }        private  static int tick=100;        public void run(){            while(true){                if(tick>0){                    System.out.println(Thread.currentThread().getName()+" sale:"+tick--);                }            }        }    }    public class SellTicket {         public static void main(String[] args) {            // TODO Auto-generated method stub            Ticket t1=new Ticket("t1--");            Ticket t2=new Ticket("t2--");            Ticket t3=new Ticket("t3--");            Ticket t4=new Ticket("t4--");            t1.start();            t2.start();            t3.start();            t4.start();        }    }

采用方法二:
synchronized用于同步代码块
原因:没有synchronized时发现打印除-1,0等错票,即多线程的运行出现了安全问题
问题产生原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
另一个线程参与进来执行,导致共享数据的错误

        class Ticket implements Runnable{                        private  int tick=100;                        Object obj=new Object();                        public void run(){                            while(true){                                synchronized (obj) {                                        if(tick>0){                                        //不能抛出异常,原因是:run方法复写了父类的run方法,父类没有设置抛出,因而不能抛出异常,只能处理异常                                    try {                                        Thread.sleep(10);                                    } catch (InterruptedException e) {                                        e.printStackTrace();                                    }                                    System.out.println(Thread.currentThread().getName()+" sale:"+tick--);                                }                                }                            }                        }                    }                    public class SellTicket {                        public static void main(String[] args) {                            Ticket t=new Ticket();                            Thread t1=new Thread(t);//创建了四个线程                            Thread t2=new Thread(t);                            Thread t3=new Thread(t);                            Thread t4=new Thread(t);                            t1.start();                            t2.start();                            t3.start();                            t4.start();                        }                    }    ```

五. 单例模式与同步块

1.单例模式有两种:饿汉式和懒汉式
饿汉式单例模式代码

class Single{  private static final Single a=new Single();  private Single();  public static Single getInstance(){        return a;        }  }

懒汉式单例模式代码

class Single{    private static Single a=null;    private Single(){}    public static  Single getInstance(){        if(a==null)        {            synchronized(Single.class){            if(a==null)                a=new Single();            }        }        return a;    }}

2.
(1)饿汉式与懒汉式区别
饿汉式用于延迟加载
(2)饿汉式的单例模式带来的问题
带来安全问题,可能由于多个线程实例化多个对象
(3)怎样解决安全问题:
同步
有两种方式:同步代码块和同步函数
(4)同步带来的问题
需要判断是否已经实例化对象,效率低下
(5)如何解决这个问题
使用同步代码块进行双重判断

六. 死锁

产生死锁的代码块

class Te implements Runnable{    private boolean flag;    Te(boolean flag){        this.flag=flag;    }    public void run(){        if(flag){            synchronized(MyLock.looka )            {              System.out.println("if looka");                synchronized(MyLock.lookb ){                System.out.println("if lookb");                }            }        }        else{            synchronized(MyLock.lookb){                System.out.println("else lookb");                synchronized(MyLock.looka){                    System.out.println("else looka");                }            }        }    }    }class MyLock{    static Object looka=new Object();    static Object lookb=new Object();}public class DeadLockTest {    public static void main(String[] args) {        Thread t1=new Thread(new Te(true));        Thread t2=new Thread(new Te(false));        t1.start();        t2.start();    }}
0 0
原创粉丝点击