黑马程序员——多线程(二)

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分(CPU就切换到另外的线程去),还没有执行完,另一个线程参与进来执行。会导致共享数据的错误。
解决办法:加同步
同步代码块

用synchronized关键字来进行定义。

同步代码块格式

synchronized(唯一对象){

需要被同步的代码;

}

对象如同锁,持有锁的线程可以在同步中执行。
没有持有锁的线程即使获取CPU的执行权,也进不去,因为没有获取锁。

好处:解决了多线程的安全问题。

弊端:多个线程需要判断锁,较为消耗资源,

同步的前提:

1,必须要有两个或者两个以上的线程。

2,必须是多个线程使用同一个锁。

同步函数:

所谓的同步函数就是在函数的返回值前面加一个synchronized关键字就是同步函数了。
同步函数的琐是所属函数this,同步函数被静态修饰后,使用的锁是该类对应的字节码文件对象,
举例:延迟加载单例之懒汉式 —面试考点多

package com.itheima1;

public class danli {
    private static danli danli = null;
    private danli() {
        // TODO Auto-generated constructor stub
    }
    public static danli asd() {
          if(danli==null)//避免每次都判断锁,提高效率 
          {
              synchronized(danli.class)//加锁
              {
                  if(danli==null){//再次判断,确保对象止创建一次
                      danli=new danli();
                  }
              }
          }
        return danli;
    }
}

线程同步注意的问题:
由于线程同步代码中可能嵌套同步,容易导致的问题就是死锁。程序就停在那里不动了。

class MyLock {

    public static Object locka = new Object();

    public static Object lockb = new Object();

}

class DeadLockTest implements Runnable {

    private boolean flag;

    DeadLockTest(boolean flag) {

        this.flag = flag;

    }

    public void run() {

        if (flag) {

            while (true) {

                synchronized (MyLock.locka) {

System.out.println(Thread.currentThread().getName()

                    + "...if locka ");

                    synchronized (MyLock.lockb) {
                        System.out.println(Thread.currentThread().getName()

                        + "..if lockb");

                    }

                }

            }

        }

        else {

            while (true) {

                synchronized (MyLock.lockb) {

                    System.out.println(Thread.currentThread().getName()

                    + "..else lockb");

                    synchronized (MyLock.locka) {

                        System.out.println(Thread.currentThread().getName()

                        + ".....else locka");

                    }

                }

            }

        }

    }

}

class Test {

    public static void main(String[] args) {

        Thread t1 = new Thread(new DeadLockTest(true));

        Thread t2 = new Thread(new DeadLockTest(false));

        t1.start();

        t2.start();

    }

}

线程间通信-等待唤醒机制

wait(),notify(),notifyAll(),都使用在同步中,因为要对持有监视器(锁)的线程操作。

思考:

wait(), notify() ,notifyAll(),用来操作线程的方法为什么定义在了Object类中?

因为这些方法在操作同步中,线程同步,都必须要表示它们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁notify唤醒,不可以对不同锁中的线程进行等待唤醒。

也就是说,等待和唤醒必须是同一个锁。所以要使用在同步中,因为只有同步才具有锁。

public class Day12Test1 {

        public static void main(String[] args) {

                Resouce r = new Resouce();
                new Thread(new Producer(r)).start();
                new Thread(new Producer(r)).start();
                new Thread(new Consumer(r)).start();
                new Thread(new Consumer(r)).start();
        }

}

class Resouce{

        private String name;
        private int count = 1;
        private boolean flag = false;
        public synchronized void set(String name){

                while(flag)//用while判断避免唤醒本方线程 重复消费或者生产
                        try{
                                wait();
                        }
                        catch(Exception e){
//                                throw new RuntimeException();
                        }
                        this.name = name + count++;
                        System.out.println(Thread.currentThread().getName()+"...生产者......"+this.name);
                        flag = true;
                        notifyAll();//唤醒全部线程避免全部等待
        }
        public synchronized void out(){
                while(!flag)
                        try{
                                wait();
                        }
                        catch(Exception e){
//                                throw new RuntimeException();
                        }
                        System.out.println(Thread.currentThread().getName()+"+消费者+"+this.name);
                        flag = false;
                        notifyAll();
        }
}
class Producer implements Runnable{
        private Resouce r;
        Producer(Resouce r){
                this.r = r;
        }
        public void run(){
                while(true){
                        r.set("汉堡");
                }
        }
}
class Consumer implements Runnable{
        private Resouce r;
        Consumer(Resouce r){
                this.r = r;
        }
        public void run(){
                while(true){
                        r.out();
                }
        }
}

多线程(守护线程)(后台线程)

线程对象.setDaemon(true);将该线程标记为守护线程或用户线程。

当正在运行的线程都是守护线程时,Java虚拟机退出,程序结束。

注意:一个线程被标示为守护线程,并不是他不运行了,他跟其他线程一样运行。只是当前台线程执行完后,这些线程不会结束。

多线程(Join方法)

Join():当A线程执行到了B线程的.Join()方法时,A线程就会让出CPU执行权,等待直到B线程执行完,A才会执行。

Join可以用来临时加入线程执行。

注意:碰见了谁的Join()方法,就只等谁。等他结束就执行。

多线程(优先级&yield方法)

优先级:线程对象.setPriority(intnewPriority);设置线程优先权,1-10,默认5,越大,抢到CPU执行权机会越大;

(Thread.MAX_PRIORITY, MIN_PRIORITY ,NORM_PRIORITY)

static void yield():暂停当前正在执行的线程,并执行其他线程,Thread.yield();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值