——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();