java——多线程2
1.线程局部变量的共享
1.1共享一个变量的情况
使用Map集合(键值对),key放线程对象,value放共享的数据
代码实现:
package com.dream.thread01;
import java.util.concurrent.ConcurrentHashMap;
public class Test01 {
public static ConcurrentHashMap<Thread, Integer> map = new ConcurrentHashMap<>();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
int i = 10;
//存数据
map.put(Thread.currentThread(), i);
A a = new A();
B b = new B();
a.println();//10
b.println();//10
}
},"线程1").start();
new Thread(new Runnable() {
@Override
public void run() {
int i = 20;
//存数据
map.put(Thread.currentThread(), i);
A a = new A();
B b = new B();
a.println();//20
b.println();//20
}
},"线程2").start();
}
}
package com.dream.thread01;
public class A {
public void println(){
Thread thread = Thread.currentThread();
Integer value = Test01.map.get(thread);
System.out.println(thread.getName() + "中的A类对象调用了println() -- " + value);
}
}
package com.dream.thread01;
public class B {
public void println(){
Thread thread = Thread.currentThread();
Integer value = Test01.map.get(thread);
System.out.println(thread.getName() + "中的B类对象调用了println() -- " + value);
}
}
1.2共享多个变量的情况
创建一个实体类进行存储共享的数据
代码实现:
package com.dream.thread02;
public class A {
public void println(){
Thread thread = Thread.currentThread();
Data value = Test01.map.get(thread);
System.out.println(thread.getName() + "中的A类对象调用了println() -- " + value);
}
}
package com.dream.thread02;
public class B {
public void println(){
Thread thread = Thread.currentThread();
Data value = Test01.map.get(thread);
System.out.println(thread.getName() + "中的B类对象调用了println() -- " + value);
}
}
package com.dream.thread02;
//数据包类
public class Data {
private int i;
private String str;
public Data() {
}
public Data(int i, String str) {
this.i = i;
this.str = str;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Data [i=" + i + ", str=" + str + "]";
}
}
package com.dream.thread02;
import java.util.concurrent.ConcurrentHashMap;
public class Test01 {
public static ConcurrentHashMap<Thread, Data> map = new ConcurrentHashMap<>();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
Data data = new Data(10,"aaa");
//存数据
map.put(Thread.currentThread(), data);
A a = new A();
B b = new B();
a.println();//10
b.println();//10
}
},"线程1").start();
new Thread(new Runnable() {
@Override
public void run() {
Data data = new Data(20,"bbb");
//存数据
map.put(Thread.currentThread(), data);
A a = new A();
B b = new B();
a.println();//20
b.println();//20
}
},"线程2").start();
}
}
1.3共享多个变量的情况 - ThreadLocal
代码实现:
package com.dream.thread03;
//数据包类
public class Data {
private int i;
private String str;
private Data() {
}
private Data(int i, String str) {
this.i = i;
this.str = str;
}
//获取数据包的对象
public static Data getInstance(int i,String str){
Data data = Test01.local.get();
if(data == null){
data = new Data(i, str);
Test01.local.set(data);
}else{
data.setI(i);
data.setStr(str);
}
return data;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Data [i=" + i + ", str=" + str + "]";
}
}
package com.dream.thread03;
public class Test01 {
public static ThreadLocal<Data> local = new ThreadLocal<>();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
Data data = Data.getInstance(10,"aaa");
//存数据
local.set(data);
A a = new A();
B b = new B();
a.println();//10
b.println();//10
}
},"线程1").start();
new Thread(new Runnable() {
@Override
public void run() {
Data data = Data.getInstance(20,"bbb");
//存数据
local.set(data);
A a = new A();
B b = new B();
a.println();//20
b.println();//20
}
},"线程2").start();
}
}
2.synchronized琐
2.1synchronized同步代码块
需求:
package com.dream.thread04_type01;
public class Test01 {
public static void main(String[] args) {
/*
2.铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,
请编写多线程程序来模拟这个效果
窗口001正在销售第1000张票
窗口001正在销售第999张票
窗口002正在销售第998张票
。。。
窗口002正在销售第1张票
问题1:三个窗口都卖了1000张票,一共卖了3000张
出现原因:三个线程调用三次run方法,就有3*1000张票
解决方案:三个线程共用同一个票的变量
问题2:有些票卖了重票
出现原因:票的输出语句输出后,还没有来得及做票的减减,就被其他线程抢到CPU资源了
解决方案:票的输出语句 和 票的减减必须同时执行完毕后,才能被其他线程抢到CPU资源了 - 加锁
问题3:出现负数
出现原因: 票到了零界点(ticket=1),三个线程都进入循环中
解决方案:锁中再判断一次
锁对象:多个线程要想互斥住,就必须使用同一把锁
*/
MyThread t1 = new MyThread("窗口001");
MyThread t2 = new MyThread("窗口002");
MyThread t3 = new MyThread("窗口003");
t1.start();
t2.start();
t3.start();
}
}
package com.dream.thread04_type01;
public class MyThread extends Thread{
private static int ticket = 1000;
private static Object obj = new Object();
public MyThread(String name) {
super(name);
}
@Override
public void run() {
while(ticket > 0){
//synchronized("abc"){
//synchronized(Character.class){
synchronized(obj){
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票");
ticket--;
}
if(ticket <= 0){
System.out.println(Thread.currentThread().getName() + "票已售完");
}
}
}
}
}
2.2synchronized同步方法
package com.dream.thread04_type02;
public class Test01 {
public static void main(String[] args) {
/*
2.铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,
请编写多线程程序来模拟这个效果
窗口001正在销售第1000张票
窗口001正在销售第999张票
窗口002正在销售第998张票
。。。
窗口002正在销售第1张票
问题1:三个窗口都卖了1000张票,一共卖了3000张
出现原因:三个线程调用三次run方法,就有3*1000张票
解决方案:三个线程共用同一个票的变量
问题2:有些票卖了重票
出现原因:票的输出语句输出后,还没有来得及做票的减减,就被其他线程抢到CPU资源了
解决方案:票的输出语句 和 票的减减必须同时执行完毕后,才能被其他线程抢到CPU资源了 - 加锁
问题3:出现负数
出现原因: 票到了零界点(ticket=1),三个线程都进入循环中
解决方案:锁中再判断一次
锁对象:多个线程要想互斥住,就必须使用同一把锁
1.synchronized
同步代码块:
synchronized(锁对象){//自动上锁
...要互斥住的代码...
}//自动解锁
同步方法:
//锁对象:this
public synchronized void method01(){//自动上锁
...要互斥住的代码...
}//自动解锁
//锁对象:类的字节码文件对象
public static synchronized void method02(){//自动上锁
...要互斥住的代码...
}//自动解锁
*/
MyThread t1 = new MyThread("窗口001");
MyThread t2 = new MyThread("窗口002");
MyThread t3 = new MyThread("窗口003");
t1.start();
t2.start();
t3.start();
}
}
package com.dream.thread04_type02;
public class MyThread extends Thread{
private static int ticket = 1000;
public MyThread(String name) {
super(name);
}
@Override
public void run() {
while(ticket > 0){
method02();
}
}
//锁对象:类的字节码文件对象(MyThread.class)
public static synchronized void method02(){
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票");
ticket--;
}
if(ticket <= 0){
System.out.println(Thread.currentThread().getName() + "票已售完");
}
}
//锁对象:this
public synchronized void method01(){
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票");
ticket--;
}
if(ticket <= 0){
System.out.println(Thread.currentThread().getName() + "票已售完");
}
}
}
3.Lock琐
需求:
package com.dream.thread04_type03;
public class Test01 {
public static void main(String[] args) {
/**
2.铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,
请编写多线程程序来模拟这个效果
窗口001正在销售第1000张票
窗口001正在销售第999张票
窗口002正在销售第998张票
。。。
窗口002正在销售第1张票
问题1:三个窗口都卖了1000张票,一共卖了3000张
出现原因:三个线程调用三次run方法,就有3*1000张票
解决方案:三个线程共用同一个票的变量
问题2:有些票卖了重票
出现原因:票的输出语句输出后,还没有来得及做票的减减,就被其他线程抢到CPU资源了
解决方案:票的输出语句 和 票的减减必须同时执行完毕后,才能被其他线程抢到CPU资源了 - 加锁
问题3:出现负数
出现原因: 票到了零界点(ticket=1),三个线程都进入循环中
解决方案:锁中再判断一次
锁对象:多个线程要想互斥住,就必须使用同一把锁
Lock
Lock lock = new ReentrantLock();
lock.lock();//手动上锁
...要互斥住的代码...
lock.unlock();//手动解锁
synchronized vs Lock
synchronized:关键字层面上的锁,自动上锁和自动解锁
Lock:API层面上的锁,手动上锁和手动解锁
*/
MyThread t1 = new MyThread("窗口001");
MyThread t2 = new MyThread("窗口002");
MyThread t3 = new MyThread("窗口003");
t1.start();
t2.start();
t3.start();
}
}
package com.dream.thread04_type03;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyThread extends Thread{
private static int ticket = 1000;
private static Lock lock = new ReentrantLock();
public MyThread(String name) {
super(name);
}
@Override
public void run() {
while(ticket > 0){
lock.lock();//手动上锁
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票");
ticket--;
}
if(ticket <= 0){
System.out.println(Thread.currentThread().getName() + "票已售完");
}
lock.unlock();//手动解锁
}
}
}