线程概念:
线程创建的三种方式:
- 继承Thread类诚谢run方法
- 实现Runnable接口
- 实现Callable接口
继承Thread类,重写run方法:
public class ThreadStart02 extends Thread {
private String url;
private String name;
public ThreadStart02(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run(){
WebDownLoader wd=new WebDownLoader();
wd.downLoader(url,name);
System.out.println(name);
}
public static void main(String[] args) {
ThreadStart02 t1=new ThreadStart02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1558614086192&di=6f4bac47d0efe87d00a0bdd2d56c01e1&imgtype=0&src=http%3A%2F%2Fpic32.nipic.com%2F20130823%2F13339320_183302468194_2.jpg","first.jpg");
ThreadStart02 t2=new ThreadStart02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1558614086192&di=50912f0854a71471859254a6c91c1a33&imgtype=0&src=http%3A%2F%2Fk.zol-img.com.cn%2Fsjbbs%2F7692%2Fa7691515_s.jpg","dog.jpg");
ThreadStart02 t3=new ThreadStart02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1558614086192&di=b6c27e363372754becd7ac9489b2e7cd&imgtype=0&src=http%3A%2F%2Fpic40.nipic.com%2F20140412%2F18428321_144447597175_2.jpg","three.jpg");
t1.start();
t2.start();
t3.start();
}
}
实现Runnable接口
/**
* 推荐使用接口,避免单继承的局限性
* 方便共享资源
*/
public class ThreadStart04 implements Runnable {
private String url;
private String name;
public ThreadStart04(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run(){
WebDownLoader wd=new WebDownLoader();
wd.downLoader(url,name);
System.out.println(name);
}
public static void main(String[] args) {
ThreadStart04 t1=new ThreadStart04("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1558614086192&di=6f4bac47d0efe87d00a0bdd2d56c01e1&imgtype=0&src=http%3A%2F%2Fpic32.nipic.com%2F20130823%2F13339320_183302468194_2.jpg","first.jpg");
ThreadStart04 t2=new ThreadStart04("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1558614086192&di=50912f0854a71471859254a6c91c1a33&imgtype=0&src=http%3A%2F%2Fk.zol-img.com.cn%2Fsjbbs%2F7692%2Fa7691515_s.jpg","dog.jpg");
ThreadStart04 t3=new ThreadStart04("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1558614086192&di=b6c27e363372754becd7ac9489b2e7cd&imgtype=0&src=http%3A%2F%2Fpic40.nipic.com%2F20140412%2F18428321_144447597175_2.jpg","three.jpg");
new Thread(t1).start();
new Thread(t2).start();
new Thread(t3).start();
}
}
赛跑代码:
/**
* 模拟归途赛跑
*/
public class Reacer implements Runnable {
private static String winner;
@Override
public void run() {
for(int steps=0;steps<=100;steps++){
if(Thread.currentThread().getName().equals("兔子") && steps%10==0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"--->"+steps);
//比赛是否结束
boolean flag=gameOver(steps);
if (flag) {
break;
}
}
}
private boolean gameOver(int steps){
if(winner!=null){
return true;
}else{
if(steps==100){
winner=Thread.currentThread().getName();
System.out.println("winner==>"+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Reacer racer=new Reacer();
new Thread(racer,"兔子").start();
new Thread(racer,"乌龟").start();
}
}
Callable学习:
public class Reacer1 implements Callable<Integer> {
private static String winner;
@Override
public Integer call() throws Exception {
for(int steps=0;steps<=100;steps++){
if(Thread.currentThread().getName().equals("pool-1-thread-1") && steps%10==0){
Thread.sleep(100);
}
System.out.println(Thread.currentThread().getName()+"--->"+steps);
//比赛是否结束
boolean flag=gameOver(steps);
if (flag) {
return steps;
}
}
return null;
}
private boolean gameOver(int steps){
if(winner!=null){
return true;
}else{
if(steps==100){
winner=Thread.currentThread().getName();
System.out.println("winner==>"+winner);
return true;
}
}
return false;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Reacer1 racer=new Reacer1();
ExecutorService ser= Executors.newFixedThreadPool(2);
//开始执行
Future<Integer> result1=ser.submit(racer);
Future<Integer> result2=ser.submit(racer);
int r1=result1.get();
int r2=result2.get();
System.out.println("r1:"+r1+" r2:"+r2);
ser.shutdown();
}
}
代理模式:
/**
* 静态代理
* 接口:
* 1,真是角色
* 2,代理角色
*/
public class StaticProxy {
public static void main(String[] args) {
new WeddingCompany(new You()).happyMarry();
}
}
interface Marry{
void happyMarry();
}
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("you and 唱歌终于奔月了。。。。。");
}
}
class WeddingCompany implements Marry{
private Marry target;
public WeddingCompany(Marry target){
this.target=target;
}
@Override
public void happyMarry() {
ready();
this.target.happyMarry();
after();
}
private void ready() {
System.out.println("布置桌子");
}
public void after(){
System.out.println("结婚完毕");
}
}
lamda表达式:
避免内部类定义过多,实质属于函数式变成的概念
public class LamdaTest05 {
public static void main(String[] args) {
new Thread(()->{
for(int i=0;i<100;i++){
System.out.println("一遍学习");
}
}).start();
new Thread(()->{
for(int i=0;i<100;i++){
System.out.println("一遍泪流满面");
}
}).start();
}
}
线程状态:
常见的线程方法:
线程的停止:
sleep:
1,指定当前线程阻塞的毫秒数,占有资源
2,存在中断异常InterruptedException
2,时间到后到就绪态
public class BlockStatus03 {
public static void main(String[] args) throws InterruptedException {
//倒数是个数。一秒一个
Date dateTime=new Date(System.currentTimeMillis()+1000*10);
Long end=dateTime.getTime();
while(true){
System.out.println(new SimpleDateFormat("mm:ss").format(dateTime));
Thread.sleep(1000);
dateTime=new Date(dateTime.getTime()-1000);
if(end-10000>=dateTime.getTime()){
break;
}
}
}
public static void test() throws InterruptedException {
int num=10;
while(true){
Thread.sleep(1000);
System.out.println(num--);
}
}
}
就绪状态:
1,start()方法
2,阻塞接触
3,yield()方法
4,jvm切换
运行状态:running,cpu进行控制,一般为时间分配时间片,开始运行,可以看下os的调度
阻塞状态:
1,sleep 资源占有,然后谁卖你
2,join 在那个方法,那个方法阻塞
3,wait
4,io的read 和write犯法
public class AllState {
public static void main(String[] args) {
Thread t=new Thread(()->{
for(int i=0;i<5;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(".....");
}
});
Thread.State state=t.getState();
System.out.println(state);
t.start();
state=t.getState();
System.out.println(state);
while(state!=Thread.State.TERMINATED){
int num=Thread.activeCount();
if(num==1){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
state=t.getState();
System.out.println(state);
}
state=t.getState();
System.out.println(state);
}
}
priority:优先级
/**
* 新城优先级
* 概率:知识先后执行的概率
*/
public class PriorityTest01 {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getPriority());
MyPriority mp=new MyPriority();
Thread t=new Thread(mp,"address");
Thread t1=new Thread(mp,"NIKE");
Thread t2=new Thread(mp,"回力");
Thread t3=new Thread(mp,"361");
Thread t4=new Thread(mp,"李宁");
//设置优先级再启动之前
t.setPriority(Thread.MAX_PRIORITY);
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.NORM_PRIORITY);
t3.setPriority(Thread.MIN_PRIORITY);
t4.setPriority(Thread.MIN_PRIORITY);
t.start();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
Thread.yield();
}
}
线程分配
1,分为用户线程和守护线程
2,虚拟机必须确保用户线程执行完毕
‘3,虚拟机不用等待守护线程执行完毕
* 守护线程
* 是为用户线程服务的,JVM停止,不用等待守护线程执行完毕
* 默认都是用户用户线程,jvm等待所有的用户线程执行完毕
*/
public class DaemonTest01 {
public static void main(String[] args) {
God god=new God();
You you=new You();
Thread t=new Thread(god);
t.setDaemon(true);
t.start();
new Thread(you).start();
}
}
class You implements Runnable{
public void run(){
for(int i=0;i<365*100;i++){
System.out.println("happy life-----");
}
System.out.println("oooooo");
}
}
class God implements Runnable{
public void run(){
for(;true;){
System.out.println("bresss you-----");
}
}
}
’常用方法示例:
/**
* isAlive:线程是否还活着
* currentThread 当前线程
* setName 设置名称:代理名称
* 程序猿的劳斯莱斯
*/
public class InfoTest {
public static void main(String[] args) throws InterruptedException {
System.out.println(Thread.currentThread().isAlive());
//设置名称:真是角色+代理角色
myInfo info=new myInfo("站冬季");
Thread t=new Thread(info);
t.setName("公鸡");
t.start();
Thread.sleep(1000);
System.out.println(t.isAlive());
}
}
class myInfo implements Runnable{
private String name;
public myInfo(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--->"+name);
}
}
线程同步:
synchronized,并发控制
/**
* 取钱线程不安全
*/
public class UnsafeTest02 {
public static void main(String[] args) {
Account account=new Account(100,"结婚礼金");
Drawing you=new Drawing(account,80,"可悲的你");
Drawing wife=new Drawing(account,90,"女朋友");
you.start();
wife.start();
}
}
class Account{
int money;
String name;
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
class Drawing extends Thread{
Account account;//账户
int drawingMoney;//区签署
int drawTotal;//取钱总数
public Drawing(Account account, int drawingMoney,String name) {
super(name);
this.drawingMoney = drawingMoney;
this.account = account;
}
@Override
public void run() {
if(account.money-drawingMoney<0){
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money-=drawingMoney;
drawTotal+=drawingMoney;
System.out.println(this.getName()+"-->账户余额为"+account.money);
System.out.println(this.getName()+"-->取钱总额为"+drawTotal);
}
}
常规容易出现问题,不可避免,
女朋友-->账户余额为-70
女朋友-->取钱总额为90
可悲的你-->账户余额为-70
可悲的你-->取钱总额为80
并发原因:
1,同一个对象呗多个线程同时操作
线程同步 :当两个或两个以上线程访问同一资源时,需要某种方式来确保资源在某一时刻只被一个线程 使用。
1,队列
2,锁机制
同步监视器
• synchronized (obj){ }中的obj称为同步监视器
• 同步代码块中同步监视器可以是任何对象,但是推荐使用共享资源作为同步监视器
• 同步方法中无需指定同步监视器,因为同步方法的同步监视器是this,也就是该对象本事
同步监视器的执行过程
• 第一个线程访问,锁定同步监视器,执行其中代码
• 第二个线程访问,发现同步监视器被锁定,无法访问
• 第一个线程访问完毕,解锁同步监视器
• 第二个线程访问,发现同步监视器未锁,锁定并访问
synchronized:锁对象的资源,即this
/**
* 数据有负数或者重复
*
*/
public class SynTest01 {
public static void main(String[] args) {
SynTest0112306 web=new SynTest0112306();
new Thread(web,"码畜").start();
new Thread(web,"码农").start();
new Thread(web,"码皇").start();
}
}
class SynTest0112306 implements Runnable {
private int ticketsNum=10;
private boolean flag=true;
@Override
public void run() {
while(flag){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
test();
}
}
public synchronized void test(){
if(ticketsNum<=0){
flag=false;
return;
}
/**
* 模拟网络延时
*/
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"------>"+ticketsNum--);
}
}
同步代码块:
/**
* 取钱线程不安全
*/
public class SynTest03 {
public static void main(String[] args) {
Account2 account=new Account2(100,"结婚礼金");
Drawing2 you=new Drawing2(account,80,"可悲的你");
Drawing2 wife=new Drawing2(account,90,"女朋友");
you.start();
wife.start();
}
}
class Account2{
int money;
String name;
public Account2(int money, String name) {
this.money = money;
this.name = name;
}
}
class Drawing2 extends Thread{
Account2 account;//账户
int drawingMoney;//去签署
int drawTotal;//取钱总数
public Drawing2(Account2 account, int drawingMoney, String name) {
super(name);
this.drawingMoney = drawingMoney;
this.account = account;
}
@Override
public void run() {
test();
}
//目标锁定不确定,这里不应爱锁this
public synchronized void test(){
if(account.money-drawingMoney<0){
return;
}
synchronized (account){
if(account.money-drawingMoney<0){
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money-=drawingMoney;
drawTotal+=drawingMoney;
System.out.println(this.getName()+"-->账户余额为"+account.money);
System.out.println(this.getName()+"-->取钱总额为"+drawTotal);
}
}
}
synchronized:
package syn;
/**
* 取钱线程不安全
*/
public class SynTest03 {
public static void main(String[] args) {
Account2 account=new Account2(100,"结婚礼金");
Drawing2 you=new Drawing2(account,80,"可悲的你");
Drawing2 wife=new Drawing2(account,90,"女朋友");
you.start();
wife.start();
}
}
class Account2{
int money;
String name;
public Account2(int money, String name) {
this.money = money;
this.name = name;
}
}
class Drawing2 extends Thread{
Account2 account;//账户
int drawingMoney;//去签署
int drawTotal;//取钱总数
public Drawing2(Account2 account, int drawingMoney, String name) {
super(name);
this.drawingMoney = drawingMoney;
this.account = account;
}
@Override
public void run() {
test();
}
//目标锁定不确定,这里不应爱锁this
public void test(){
if(account.money<=0){
return;
}
synchronized (account){
if(account.money-drawingMoney<0){
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money-=drawingMoney;
drawTotal+=drawingMoney;
System.out.println(this.getName()+"-->账户余额为"+account.money);
System.out.println(this.getName()+"-->取钱总额为"+drawTotal);
}
}
}
List的方法:
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 操作容器:线程安全
*/
public class SynContainer {
public static void main(String[] args) throws InterruptedException {
CopyOnWriteArrayList<String> lists=new CopyOnWriteArrayList<>();
for(int i=0;i<10000;i++){
new Thread(()->{
lists.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(2000);
System.out.println(lists.size());
}
}
思索:多个线程各自占有共享资源,相互等待其他线程的资源释放,才能继续进行,导致多个线程等待对方释放资源,都停止执行,当一个同步块同时拥有两个以上的对象的锁的同时,就有可能发生思索问题。
1,问题的发生条件为锁套锁,即出现多个锁
/**
* @author lsd
* 思索
*/
public class DeadLock {
public static void main(String[] args) {
Markup g1=new Markup(1,"大牙");
Markup g2=new Markup(0,"王菲");
g1.start();
g2.start();
}
}
class Lipstick{
}
class Mirror{
}
class Markup extends Thread{
static Lipstick lipstick=new Lipstick();
static Mirror mirror=new Mirror();
int choice;
String girl;
public Markup(int choice,String girl) {
this.choice = choice;
this.girl=girl;
}
//相互持有对方的对象锁
public void markup(){
if(choice==0){
synchronized (lipstick){
System.out.println(this.girl+"获得口红");
//一秒后想拥有镜子的锁
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (mirror){
System.out.println(this.girl+"获得镜子");
}
}else{
synchronized (mirror){
System.out.println(this.girl+"获得镜子");
//一秒后想拥有镜子的锁
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (lipstick){
System.out.println(this.girl+"获得口红");
}
}
}
@Override
public void run(){
markup();
}
}
线程的写作:
生产者消费者模型:
管程法:解耦,缓冲区,互相不关联
3个角色:生产者,消费者,并发容器
信号灯法:
/**
* 生产者消费者实现方式一:信号灯
*/
public class CodeTest02 {
public static void main(String[] args) {
Tv con=new Tv();
new Player(con).start();
new Watcher(con).start();
}
}
//生产者 演员
class Player extends Thread{
Tv tv;
public Player(Tv tv) {
this.tv = tv;
}
@Override
public void run() {
for(int i=0;i<20;i++){
if (i % 2 == 0) {
try {
this.tv.play("奇葩说");
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
try {
this.tv.play("太污了,喝瓶礼拜嘻嘻最");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
//消费者 观众
class Watcher extends Thread{
Tv tv;
public Watcher(Tv tv) {
this.tv = tv;
}
@Override
public void run() {
for(int i=0;i<20;i++){
if (i % 2 == 0) {
try {
this.tv.watch();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
try {
this.tv.watch();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
//同一个资源 电视
class Tv{
String voice;
//信号灯 t演员表演 观众等待
boolean flag=true;
public synchronized void play(String voice) throws InterruptedException {
//演员等待
if(!flag){
this.wait();
}
System.out.println("表演了"+voice);
this.voice=voice;
this.notifyAll();
this.flag=!this.flag;
}
public synchronized void watch() throws InterruptedException {
//观众等待
if(flag){
this.wait();
}
System.out.println("听到了"+voice);
this.notifyAll();
//切换标志
this.flag=!this.flag;
}
}
管程法:
/**
* 生产者消费者实现方式一:管程法
*/
public class CodeTest01 {
public static void main(String[] args) {
SynContainer con=new SynContainer();
new Productor(con).start();
new Comsumer(con).start();
}
}
//生产者
class Productor extends Thread{
SynContainer synContainer;
public Productor(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("生产第"+i+"个馒头");
synContainer.push(new Steamedbun(i));
}
}
}
//消费者
class Comsumer extends Thread{
SynContainer synContainer;
public Comsumer(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("消费第"+synContainer.pop().id+"个馒头");
}
}
}
//缓冲区
class SynContainer{
Steamedbun[] bums=new Steamedbun[10];
int count=0;//计数器
//存储
public synchronized void push(Steamedbun bun){
//不能生产
if(count==bums.length){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
bums[count]=bun;
count++;
this.notifyAll();
}
//获取
public synchronized Steamedbun pop(){
if(count==0){
try {
this.wait();//此时线程阻塞,生产者通知消费,线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
Steamedbun bun=bums[count];
this.notifyAll();
return bun;
}
}
//馒头
class Steamedbun{
int id;
public Steamedbun(int id) {
this.id = id;
}
}
任务定时调度:
import java.util.*;
public class MyTimerTest01 {
public static void main(String[] args) {
Timer timer=new Timer();
Calendar c=new GregorianCalendar(2099,12,31,21,53,54);
timer.schedule(new MyTask(),c.getTime(),1000);
}
}
//任务类,多线程
class MyTask extends TimerTask {
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("放松大脑,放松会");
}
System.out.println("------end-----");
}
}
定时器调度:spring集成
/**
* This Example will demonstrate how to start and shutdown the Quartz scheduler and how to schedule a job to run in
* Quartz.
*
* @author Bill Kratzer
*/
public class QuartzTest {
public void run() throws Exception {
Logger log = LoggerFactory.getLogger(QuartzTest.class);
log.info("------- 初始化 ---------");
// 1,创建Scheduler工厂
SchedulerFactory sf = new StdSchedulerFactory();
//2,从工厂中获取调度器
Scheduler sched = sf.getScheduler();
// 设置时间
Date runTime = evenSecondDate(new Date());
// 3,创建JobDetail
JobDetail job = newJob(HelloJob.class).withIdentity("job1", "group1").build();
// 4.触发器
Trigger trigger = newTrigger().withIdentity("trigger1", "group1").startAt(runTime).withSchedule(simpleSchedule().withIntervalInSeconds(5).withRepeatCount(3)).build();
// 5,注册任务和触发条件
sched.scheduleJob(job, trigger);
sched.start();
log.info("------- 任务调度开始 -----------------");
// wait long enough so that the scheduler as an opportunity to
// run the job!
log.info("------- 5秒之后调度. -------------");
try {
// 5秒后停止
Thread.sleep(65L * 1000L);
} catch (Exception e) {
e.printStackTrace();
}
log.info("------- 结束调度 ---------------------");
sched.shutdown(true);
}
public static void main(String[] args) throws Exception {
QuartzTest example = new QuartzTest();
example.run();
}
}
HappenBefore:
写的代码可能没按照自己想要的顺序去执行。
执行顺序:
1,获取指令
2,解码翻译 寄存器取值
3,操作
4,写回寄存器
public class HappenBerore {
private static int a=0;
private static boolean flag=false;
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<100;i++){
a=0;
flag=false;
Thread t=new Thread(()->{
a=1;
flag=true;
});
Thread t2=new Thread(()->{
if(flag){
a*=1;
}
if(a==0){
System.out.println("happen_before "+a);
}
});
t.start();
t2.start();
t.join();
t2.join();
}
}
}
结果为:
happen_before 1
happen_before 0
happen_before 0
happen_before 0
happen_before 0
volatile:只保证同步的数据可见。
/**
* 用于保证数据的同步,也就是可见性
* @author lsd
*/
public class VolatileTest {
private volatile static int num=0;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
while(num==0){
}
}).start();
Thread.sleep(1000);
num=1;
}
}
单例模式:
/**
* 单例模式:套路,多线程环境下对外存在一个对象
* 1,构造器私有化--》避免外部new构造器
* 2,提供私有的静态属性--》存储对象的地址
* 3,提供公共的静态方法--》获取属性
*/
public class DoubleCheckedLocking {
//私有静态属性
private volatile static DoubleCheckedLocking instance;
//构造器私有化
private DoubleCheckedLocking(){
}
public static DoubleCheckedLocking getInstance(){
if(instance!=null){//避免不必要的
return instance;
}
synchronized(DoubleCheckedLocking.class){
if(null==instance){
instance=new DoubleCheckedLocking();
//开辟空间,初始化对象信息,返回对象的地址引用
}
}
return instance;
}
public static void main(String[] args) {
new Thread(()->{
System.out.println(DoubleCheckedLocking.getInstance());
}).start();
System.out.println(DoubleCheckedLocking.getInstance());
}
}
ThreadLocal:
/**
* ThreadLocal:需要分析上下文环境,七点
* 1,构造器,哪里调用就属于哪里
*/
public class ThreadLocalTest3 {
private static ThreadLocal<Integer> threadLocal=ThreadLocal.withInitial(()->1);
public static void main(String[] args) {
new Thread(new MyRun()).start();
new Thread(new MyRun()).start();
}
public static class MyRun implements Runnable{
public MyRun(){
threadLocal.set(20);
System.out.println(Thread.currentThread().getName()+"还剩下---->"+threadLocal.get());
}
@Override
public void run() {
Integer left=threadLocal.get();
System.out.println(Thread.currentThread().getName()+"得到了---->"+left);
threadLocal.set(left-1);
System.out.println(Thread.currentThread().getName()+"还剩下---->"+threadLocal.get());
}
}
}