您的位置:首页 > 职场人生

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

2015-07-25 13:12 465 查看
——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();
}

4000
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();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多线程 同步