黑马程序员 多线程

——- 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培训、期待与您交流! ———-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值