1,同步代码块

-格式:

synchronized(对象){

需要同步的代码;

}

-注意:这个对象,同步代码块可以解决线程安全问题的根本就在于这个对象。

这个对象就好比是锁的功能。

-这个对象可以是任意对象,但是多个线程必须是同一个对象。

2,同步的好处:

-解决了多线程中的线程安全问题

3,同步的弊端

-当线程很多的时候,因为每个线程来了之后都要判断同步上的锁,这个很

耗费资源和时间,降低了程序的运行效率。

package com.momo.thread;

import com.momo.domain.Stu;

public class MyRunnable implements Runnable{

private int tickets = 100;

// Object o = new Object();

Stu s = new Stu();

@Override

public void run() {

while (true){

// synchronized (new Object()) {//注意不能这样

synchronized (s) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

if (tickets > 0) {

System.out.println(Thread.currentThread().getName() + "卖出了第:" + (tickets--) + "张票");

}

}

}

}

}

package com.momo.demo;

import com.momo.thread.MyRunnable;

public class Demo1 {

public static void main(String[] args) {

MyRunnable mr = new MyRunnable();

Thread t1 = new Thread(mr,"都美竹");

Thread t2 = new Thread(mr,"小龙女");

Thread t3 = new Thread(mr,"都美艳");

t1.start(); t2.start(); t3.start(); }

}

package com.momo.thread;

import com.momo.domain.Stu;

public class MyRunnable implements Runnable{

// private int tickets = 100;

private static int tickets = 100;

// Object o = new Object();

private Stu s = new Stu();

private int i = 0;

@Override public void run() { while (true){ if(i%2==0){ // synchronized (s) { // synchronized (this) { synchronized (MyRunnable.class) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖出了第:" + (tickets--) + "张票"); } } }else{ /* synchronized (s) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖出了第:" + (tickets--) + "张票"); } }*/ // maiPiao(); // maiPiao2(); maiPiao3(); } i++; } } /* * 静态同步方法的锁对象是当前类的字节码文件对象 MyRunnable.class * */ private static synchronized void maiPiao3(){ if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖出了第:" + (tickets--) + "张票"); } } /* * 同步方法:就是把同步关键字加到方法上 * 锁对象是this * */

/* private synchronized void maiPiao2(){

if (tickets > 0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + "卖出了第:" + (tickets--) + "张票");

}

}//

* 如果一个方法从刚开始就发现它里面的代码被同步了,那么

* 就可以把这个同步加到方法上, 就变成了同步方法。

* //

synchronized (s) {

if (tickets > 0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + "卖出了第:" + (tickets--) + "张票");

}

}

}//

public void run() {

while (true){

// synchronized (new Object()) {//注意不能这样

synchronized (s) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

if (tickets > 0) {

System.out.println(Thread.currentThread().getName() + "卖出了第:" + (tickets--) + "张票");

}

}

}

}*/

}

package com.momo.demo;

import com.momo.thread.MyRunnable;

public class Demo1 {

public static void main(String[] args) {

MyRunnable mr = new MyRunnable();

Thread t1 = new Thread(mr,"都美竹");

Thread t2 = new Thread(mr,"小龙女");

Thread t3 = new Thread(mr,"都美艳");

t1.start(); t2.start(); t3.start(); }

}

一,解决线程安全问题方式二 1,同步方法 -把同步关键字加到方法上 2,同步方法的锁对象是 this 3,静态同步方法的锁对象是 当前类字节码文件对象 4,到底用哪个? -如果锁对象是this,就可以考虑用同步方法。 一般来说能用同步代码块就用同步代码块

二,后来jdk提供的新锁 Lock 锁

1,虽然我们可以使用同步机制解决线程安全问题,

但是我们看不到它到底是在哪里上锁的,又是在哪里开锁的。

为了能够更加清楚的表示上锁和解锁,后来就提供了lock锁。

2,Lock 接口

void lock()

获得锁。

void unlock()

释放锁。

3,实现类

ReentrantLock

package com.momo.thread;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class MyRunnable2 implements Runnable{

private int tickets = 100;

private Lock l = new ReentrantLock();

@Override

public void run() {

while (true){

try {

l.lock();

if (tickets > 0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + "卖出了第:" + (tickets--) + "张票");

}

}finally {

l.unlock();

}

}

}

}

package com.momo.demo;

import com.momo.thread.MyRunnable;

import com.momo.thread.MyRunnable2;

public class Demo2 {

public static void main(String[] args) {

MyRunnable2 mr = new MyRunnable2();

Thread t1 = new Thread(mr,"都美竹");

Thread t2 = new Thread(mr,"小龙女");

Thread t3 = new Thread(mr,"都美艳");

t1.start(); t2.start(); t3.start(); }

}

三,同步注意事项:

1,注意死锁

-如果出现了同步嵌套,就很容易产生死锁

-指的是2个或2个以上的线程在执行过程中,以为争夺资源产生的一种相互等待的现象

package com.momo.thread;

import com.momo.domain.MyLock;

public class DieLock extends Thread{

private boolean boo;

public DieLock(boolean boo){

this.boo = boo;

}

@Override public void run() { if(boo){ synchronized (MyLock.O1){ System.out.println("if 的 o1"); synchronized (MyLock.O2){ System.out.println("if 的 o2"); } } }else{ synchronized (MyLock.O2){ System.out.println("else 的 o2"); synchronized (MyLock.O1){ System.out.println("else 的 o1"); } } } }

}

package com.momo.demo;

import com.momo.thread.DieLock;

public class Demo3 {

public static void main(String[] args) {

DieLock d1 = new DieLock(true);

DieLock d2 = new DieLock(false);

d1.start(); d2.start(); }

}

package com.momo.domain;

public class MyLock { public static final Object O1 = new Object(); public static final Object O2 = new Object(); }

四,线程之间的通信

1,有买票的,也会有退票的。

package com.momo.demo;

import com.momo.domain.BaoZi;

import com.momo.thread.GetBaoZi;

import com.momo.thread.SetBaoZi;

//测试类

/*

  • 问题一:为了让效果更加明显,加入了循环和判断,
  • 同一个数据出现多次
  • 名字和价格不匹配
  • 如果是消费者线程先抢到cpu的执行权,输出是null和0
  • 原因:
  • 同一个数据出现多次
  • cpu的一点点时间足够我们的代码执行很多次
  • 名字和价格不匹配
  • 线程的执行是随机的
  • 也就是说我们的代码存在线程安全问题:
  • 是否是多线程 是
  • 是否有共享数据 有
  • 是否有多条语句操作共享数据 有
  • 解决方式:加锁
  • 注意:不同种类的线程都要加锁,还必须是同一个锁
  • */

public class Demo4 {

public static void main(String[] args) {

//创建子类源

BaoZi b = new BaoZi();

//创建生产者和消费者线程

SetBaoZi sb = new SetBaoZi(b);

GetBaoZi gb = new GetBaoZi(b);

gb.start(); sb.start();

}

}

package com.momo.domain;

//资源类

public class BaoZi {

private String name;

private int price;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getPrice() {

return price;

}

public void setPrice(int price) {

this.price = price;

}

}

package com.momo.thread;

import com.momo.domain.BaoZi;

//消费者线程

public class GetBaoZi extends Thread{

private BaoZi bz;//BaoZi bz = new Baozi();

public GetBaoZi(BaoZi bz){

this.bz = bz;

}

@Override

public void run() {

while (true) {

synchronized (bz) {

System.out.println("我买到了一个:" + bz.getName() + ",价格是:" + bz.getPrice());

}

}

}

}

package com.momo.thread;

import com.momo.domain.BaoZi;

//生产者线程

public class SetBaoZi extends Thread{

private BaoZi bz;//BaoZi bz = new Baozi();

private int i = 0;

public SetBaoZi(BaoZi bz){

this.bz = bz;

}

@Override public void run() { while (true) { synchronized (bz) { if (i % 2 == 0) { bz.setName("菜包子"); bz.setPrice(1); //BaoZi bz = new Baozi("菜包子",1); } else { bz.setName("肉包子"); // BaoZi bz = new Baozi("肉包子",1); bz.setPrice(2); } System.out.println("我生产了一个:" + bz.getName() + ",价格是:" + bz.getPrice()); i++; } } }

}

package com.momo.demo;

import com.momo.domain.Dumplings;

import com.momo.thread.GetDumplings;

import com.momo.thread.SetDumplings;

public class Demo5 {

public static void main(String[] args) {

Dumplings d = new Dumplings();

SetDumplings sd = new SetDumplings(d); GetDumplings gd = new GetDumplings(d); Thread t1 = new Thread(sd); Thread t2 = new Thread(gd); t2.start(); t1.start(); }

}

package com.momo.domain;

//资源

public class Dumplings {

private String name;

private int price;

public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; }

}

package com.momo.thread;

import com.momo.domain.Dumplings;

//生产者线程

public class SetDumplings implements Runnable{

private Dumplings d;

private int i = 0;

public SetDumplings(Dumplings d){

this.d = d;

}

@Override

public void run() {

while (true) {

synchronized (d) {

if (i % 2 == 0) {

d.setName("素饺子");

d.setPrice(1);

} else {

d.setName("肉饺子");

d.setPrice(2);

}

System.out.println("生产者:" + d.getName() + "---" + d.getPrice());

i++;

}

}

}

}

package com.momo.thread;

import com.momo.domain.Dumplings;

//消费者线程 public class GetDumplings implements Runnable{ private Dumplings d; public GetDumplings(Dumplings d){ this.d = d; } @Override public void run() { while (true) { synchronized (d) { System.out.println("消费者:" + d.getName() + "---" + d.getPrice()); } } } }

-看图:等待唤醒机制图

2,上面代码加入同步之后,虽然把线程安全问题解决了。

但是依然存在一些问题。

-如果一开始就是消费者抢到cpu的执行权,就会消费,出现null和0

-如果一开始就是生产者获取执行权,一直生产也不合适。

-如果生产者生产了一个,结果消费者消费了多次也不合适。

-我们想实现的是生产一个消费一个,。。。。

-使用java提供的等待唤醒机制,用到的就是Object类中的方法:

void notify()

唤醒正在等待对象监视器的单个线程。

void notifyAll()

唤醒正在等待对象监视器的所有线程。

void wait()

导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。

void wait(long timeout)

导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过。

-问:为什么这几个方法定义在Object类中? 不在Thread类中?

这些方法必须使用锁对象来调用,而我们的锁对象可以是任意对象。

Object可以表示任意对象,所以这些方法在Object中。

package com.momo.demo;

import com.momo.domain.Dumplings;

import com.momo.thread.GetDumplings;

import com.momo.thread.SetDumplings;

public class Demo5 {

public static void main(String[] args) {

Dumplings d = new Dumplings();

SetDumplings sd = new SetDumplings(d); GetDumplings gd = new GetDumplings(d); Thread t1 = new Thread(sd); Thread t2 = new Thread(gd); t2.start(); t1.start(); }

}

package com.momo.domain;

//资源

public class Dumplings {

private String name;

private int price;

public boolean boo;//默认值false,表示没有数据。true表示有数据。

public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; }

}

package com.momo.thread;

import com.momo.domain.Dumplings;

//生产者线程

public class SetDumplings implements Runnable{

private Dumplings d;

private int i = 0;

public SetDumplings(Dumplings d){

this.d = d;

}

@Override

public void run() {

while (true) {

synchronized (d) {

if(d.boo){//true 表示有数据

try {

d.wait();//生产者等待。

} catch (InterruptedException e) {

e.printStackTrace();

}

}

if (i % 2 == 0) {

d.setName("素饺子");

d.setPrice(1);

} else {

d.setName("肉饺子");

d.setPrice(2);

}

System.out.println("生产者:" + d.getName() + "---" + d.getPrice());

i++;

d.boo = true;//修改标记 d.notify();//唤醒 消费者 并不是说它可以直接执行,还是需要抢cpu的执行权。 } } }

}

package com.momo.thread;

import com.momo.domain.Dumplings;

//消费者线程

public class GetDumplings implements Runnable{

private Dumplings d;

public GetDumplings(Dumplings d){

this.d = d;

}

@Override

public void run() {

while (true) {

synchronized (d) {

if(!d.boo){//false没有数据 !false = true

try {

d.wait();//消费者等待, 释放锁。

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println("消费者:" + d.getName() + "---" + d.getPrice());

d.boo = false;//修改标记

d.notify();//唤醒 生产者

/* if(d.boo){ System.out.println("消费者:" + d.getName() + "---" + d.getPrice()); }else{ try { d.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }*/ } } }

}

3,多线程的生命周期状态图

-看图

五,线程组

1,线程组:把多个线程分到一起,方便我们对多个线程进行统一的管理。

2,java中使用ThreadGroup 来表示线程组,把多个线程可以放到一组。

使用线程组就可以一次对多个线程进行控制和管理。

-默认情况下,所有的线程都属于主线程组。 main组

ThreadGroup getThreadGroup()

返回此线程所属的线程组。

String getName()

返回此线程组的名称。

-我们也可以设置线程组

Thread(ThreadGroup group, Runnable target)

分配一个新的 Thread对象。

Thread(ThreadGroup group, Runnable target, String name)

分配一个新的 Thread对象,使其具有 target作为其运行对象,具有指定的 name作为其名称,属于 group引用的线程组。

Thread(ThreadGroup group, String name)

分配一个新的 Thread对象。

package com.momo.demo;

import com.momo.thread.MyRunna;

/*

  • 线程组
  • /

public class Demo6 {public static void main(String[] args) {// System.out.println(Thread.currentThread().getThreadGroup().getName());/

Thread t1 = new Thread(m,"美女一号");

Thread t2 = new Thread(m,"美女二号");*/

/* ThreadGroup tg1 = t1.getThreadGroup(); ThreadGroup tg2 = t2.getThreadGroup(); String n1 = tg1.getName(); String n2 = tg2.getName(); System.out.println(n1); System.out.println(n2);*/ ThreadGroup tg = new ThreadGroup("三国组"); MyRunna m = new MyRunna(); Thread t1 = new Thread(tg,m,"貂蝉"); Thread t2 = new Thread(tg,m,"孙尚香"); Thread t3 = new Thread(tg,m,"黄月英"); System.out.println(t1.getThreadGroup().getName()); System.out.println(t2.getThreadGroup().getName()); System.out.println(t3.getThreadGroup().getName()); // tg.setDaemon(true);

}

}

package com.momo.thread;

public class MyRunna implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName()+":"+i); } } }

package com.momo.demo;

import com.momo.domain.Girl;

import com.momo.thread.GetThread;

import com.momo.thread.SetThread;

/*

  • 改进版的生产者和消费者
  • 把资源类的成员私有
  • 把生产和消费用方法封装,将来在线程中调用方法即可。
  • */

public class Demo7 {

public static void main(String[] args) {

Girl g = new Girl();

GetThread gt = new GetThread(g);

SetThread st = new SetThread(g);

Thread t1 = new Thread(gt); Thread t2 = new Thread(st); t1.start(); t2.start();

}

}

package com.momo.domain;

//资源类

public class Girl {

private String name;

private int age;

private boolean boo;

public synchronized void setGirl(String name,int age){

if(this.boo){

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

this.name = name;

this.age = age;

System.out.println("我new了一个:"+name+"---"+age);

this.boo = true;

this.notify();

}

public synchronized void getGirl(){

if(!this.boo){

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println(this.name+"--"+this.age);

this.boo = false;

this.notify();

}

}

package com.momo.thread;

import com.momo.domain.Girl;

public class SetThread implements Runnable{

private Girl g;

private int i = 0;

public SetThread(Girl g){

this.g = g;

}

@Override

public void run() {

while (true) {

if (i % 2 == 0) {

g.setGirl("哈尼克子", 18);

} else {

g.setGirl("苍老师", 30);

}

i++;

}

}

}

package com.momo.thread;

import com.momo.domain.Girl;

public class GetThread implements Runnable{ private Girl g; public GetThread(Girl g){ this.g = g; } @Override public void run() { while (true){ g.getGirl(); } } }