黑马程序员 多线程

来源:互联网 发布:mysql fetch object 编辑:程序博客网 时间:2024/06/06 17:20

——- android培训、java培训、期待与您交流! ———-

1,进程与线程:

进程是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径或者叫一个控制单元。
线程就是进程中的一个独立的控制单元,线程在控制着进程的执行。
注意:jvm启动不止一个线程,除了主线程还有负责垃圾回收机制的线程。

2,创建线程的第一种方式:继承Thread类

(a)创建子类对象的同时就创建了线程,创建多少个子类对象就有多少条线程。

(b)步骤:
(1)定义类继承Thread。
(2)复写Thread类中的run方法。目的:将自定义代码存储在 run方法。让线程运行。
(3)调用线程的start方法。该方法两个作用:启动线程;调用 run方法。
(4)要是只调用run方法,这仅仅是调用对象的方法,而没有启动线程。
(c)多线程有一个特点:随机性。在互相抢夺cpu的执行权。
(d)线程都有自己默认的名称,Thread-编号 该编号从0开始。
static Thread currentThread():获取当前线程对象。
getName(): 获取线程名称。
设置线程名称:setName或者构造函数。
线程的状态图:
线程状态图

体现

public class Thread001 {    public static void main(String[] args) {                Deme d = new Deme();        d.start();  //开启线程          for (int i = 0; i < 60; i++) {//主线程            System.out.println("main::"+i);        }    }}class Deme extends Thread{  //继承Thread类    public void run(){      //自定义方法内容        for (int i = 0; i < 60; i++) {            System.out.println("Thread::"+i);        }    }}

结果图:
结果图

3,创建线程的第二种方式:实现Runnable接口

步骤:
(a)定义类实现Runnable接口
(b)覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中。
(c)通过Thread类建立线程对象
(d)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法。
Ticket类实现了Runnable接口
Ticket t=new Ticket();
Thread t1=new Thread(t)

4,实现方式和继承方式的区别

继承Thread:线程代码存放Thread子类run方法中。
实现Runnable:线程代码存放接口的子类的run方法。实现方式的好处是避免了单继承的局限性。

5,多线程的运行出现安全问题

(a)问题的原因
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程就参与进来执行,导致共享数据的错误。

体现:

public class Thread002 {    public static void main(String[] args) {                Ticket tick = new Ticket();             Thread d1 = new Thread(tick);        Thread d2 = new Thread(tick);        Thread d3 = new Thread(tick);        Thread d4 = new Thread(tick);        d1.start();//开启线程        d2.start();//开启线程        d3.start();//开启线程        d4.start();//开启线程//      new Thread(tick).start();//      new Thread(tick).start();//      new Thread(tick).start();//      new Thread(tick).start();           }}class Ticket implements Runnable{    private int tick = 100;    public void run() {        while (true) {  //循环                    if (tick>0) {                try {                    Thread.sleep(10);//稍微等待                } catch (InterruptedException e) {                    e.printStackTrace();//处理异常                }                System.out.println(Thread.currentThread().getName()+"....."+tick--);            }               }    }}

结果图:

多线程安全问题

(b)解决办法

对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。

(c)多线程安全问题的解决办法是同步代码块:

synchronied(对象)
{需要被同步的代码}
对象如同锁。持有锁的线程可以在同步中执行,没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。例如,火车上的卫生间。

(d)同步的前提:

(1)必须要有两个或者两个以上的线程。
(2)必须是多个线程使用同一个锁,必须保证同步中只能有一个线程在运行。

(e)同步的优劣性:

(1)解决了多线程的安全问题。
(2)需要判断锁,降低效率。

(f)同步函数的锁是synchronized(this);静态同步函数的锁是synchronized(类名.class)

(g)多线程的单例设计模式

懒汉式的特点是延迟加载实例,在多线程访问时,会出现安全问题,可以使用同步代码块或同步函数来解决,但比较低效,可以通过双重判断的形式来解决低效问题。同步所使用的锁是该类字节码文件对象。

体现:

//多线程单例设计模式—懒汉式  class S  {    private static S s=null;    private S (){};    public static S getIns ()    {                  if(s==null)          {              synchronized(S.class)              {                  if(s==null)                      s=new S();              }          }                  return s;    }  }  

(h)死锁:同步中嵌套同步,使用不同的锁,万万不可。

体现:

class Test{        public static void main(String[] args)        {                Thread t1 = new Thread(new Run(true));                Thread t2 = new Thread(new Run(false));                t1.start();                t2.start();        }}class Run implements Runnable{        private boolean flag;        public Run(boolean flag)        {                this.flag = flag;        }        public void run()        {                if(flag)                {                        synchronized(LockFactory.lockA)//同步锁A                        {                                System.out.println("if.....lockA");                                synchronized(LockFactory.lockB)//同步锁B                                {                                        System.out.println("if.....lockB");                                }                        }                }else                {                        synchronized(LockFactory.lockB)//同步锁B                        {                                System.out.println("else...lockB");                                synchronized(LockFactory.lockA)//同步锁A                                {                                        System.out.println("else...lockA");                                }                        }                }        }}class LockFactory//用于提供锁的类{        static LockA lockA = new LockA();        static LockB lockB = new LockB();}class LockA//锁A{}class LockB//锁B{}

6,生产者与消费者的经典实例:

对于多个生产者和消费者,需要定义while判断标记。因为要让被唤醒的线程再一次判断标记。为什么定义notifyAll,因为需要唤醒对方线程。因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。
毕老师视频中使用whlie,wait,notifyAll解决问题,我觉得在那个例子上只需改动判断条件即可实现。

体现:

public class Thread003 {    public static void main(String[] args) {        R r=new R();        P p = new P(r);        C c = new C(r);        Thread t1 = new Thread(p);        Thread t2 = new Thread(p);        Thread t3 = new Thread(c);        Thread t4 = new Thread(c);        t1.start();        t2.start();        t3.start();        t4.start();    }}class R{    private String name;    private int count = 1;    private boolean flag = true;        public synchronized void set(String name){        if (flag) {            this.name = name + "---" + count++;            System.out.println(Thread.currentThread().getName()+"...生产者..."+ this.name);            flag = false;                   }    }       public synchronized void out(){        if (!flag) {            System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);            flag = true;        }    }           }class P implements Runnable{    private R r;    P(R r){        this.r=r;    }       public void run() {             while (true) {            r.set("++商品++");                }    }}class C implements Runnable{    private R r;    C(R r){        this.r=r;    }    public void run(){        while (true) {            r.out();                    }    }   }

7,JDK1.5升级

JDK1.5中提供了多线程升级解决方案,将同步Synchronized替换成显示的Lock操作。将Object中的wait,notify,notifyAll,替换了Condition对象:await(),signal(),signalAll()。

8,停止线程

定义循环结束标记:因为线程运行代码一般都是循环,只要控制了循环即可。
使用interrupt(中断)方法:该方法是结束线程的交结状态,使线程回到运行状态中来。
注:stop方法已经过时不再使用。

9,守护线程

setDaemon(boolean on),该方法必须在启动线程前调用。守护线程依赖于主线程,当主线程运行结束,守护线程也跟着结束。
Thread t=new Thread(d);
t.setDaemon(true);
t.start();

10,join()方法

当A线程执行到了B线程的.join()方法时,A就会等待,等B线程都执行完,A才会执行。join可以用来临时加入线程执行。

11,优先级

t1.setPriority(Thread.MAX_PRIORITY);最高优先级

t2.setPriority(Thread.MIN_PRIORITY);最低优先级

t3.setPriority(Thread.NORM_PRIORITY);默认优先级

——- android培训、java培训、期待与您交流! ———-

0 0
原创粉丝点击