首页
友链
关于
留言板
推荐
电脑壁纸
在线音乐
解压游戏
Search
1
【菜谱】咖喱鸡肉盖饭
3,704 阅读
2
pycharm生成requirements.txt
1,103 阅读
3
ubuntu安装docker和docker-compose
1,019 阅读
4
celery worker启动报错:AttributeError: 'str' object has no attribute 'items'
739 阅读
5
django后台管理界面美化
638 阅读
学习
python
linux
java
菜谱
随笔
登录
Search
标签搜索
笔记
linux
python
java
实用教程
原创
编程
多线程
docker
tomcat
thread
锁
线程同步
ssm
maven
Markdown
Windows
菜谱
生活笔记
django
Dawn
累计撰写
39
篇文章
累计收到
8
条评论
首页
栏目
学习
python
linux
java
菜谱
随笔
页面
友链
关于
留言板
推荐
电脑壁纸
在线音乐
解压游戏
搜索到
2
篇与
thread
的结果
2021-07-22
线程同步及synchronized关键字实现同步的方法
1.什么叫线程同步?多个线程操作同一个资源即并发,同一个对象被多个线程同时操作(抢票等)。线程同步是为了确保线程安全,所谓线程安全指的是多个线程对同一资源进行访问时,有可能产生数据不一致问题,导致线程访问的资源并不是安全的。如果多线程程序运行结果和单线程运行的结果是一样的,且相关变量的值与预期值一样,则是线程安全的。处理多线程问题时,最天然的解决办法就是'排队',线程同步就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕,下一个线程再使用。线程同步形成条件:队列+锁但由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问的冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized,当一个线程或的对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可,但会存在以下几个问题:一个线程持有锁会导致其它所有需要此锁的线程挂起在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,从而引起性能问题如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,出现性能倒置问题## 2.实现同步机制的方法我们都知道可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized块和synchronized方法。2.1 同步代码块语法:synchronzied(obj){}obj称之为同步监视器obj可以是任何对象,但是推荐使用共享资源作为同步监视器同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class同步监视器的执行过程第一个线程访问,锁定同步监视器,执行其中代码第二个线程访问,发现同步监视器被锁定,无法访问第一个线程访问完毕,解锁同步监视器第二个线程访问,发现同步监视器没有锁,然后锁定并访问示例:public class TestUnsafeBank { public static void main(String[] args) { Account account = new Account("结婚基金", 500); Drawing drawing1 = new Drawing(account, 300, "男朋友"); Drawing drawing2 = new Drawing(account, 400, "女朋友"); drawing1.start(); drawing2.start(); } } class Account{ private String name; private int money; public Account(String name, int money) { this.name = name; this.money = money; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } } class Drawing extends Thread{ private Account account; private int drawingMoney;//取钱 private int haveMoney;//手里有的钱 public Drawing(Account account, int drawingMoney, String name){ super(name); this.account = account; this.drawingMoney = drawingMoney; } @Override public void run() { //锁得对象是变化的对象 synchronized (account){ //同步代码块,同步监视器是银行账户 if (drawingMoney > account.getMoney()){ System.out.println(this.getName() + "取钱时账户钱不够"); return; } //模拟延时 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } account.setMoney(account.getMoney() - drawingMoney); haveMoney = haveMoney + drawingMoney; System.out.println(this.getName() + "手里现在有:" + haveMoney); System.out.println("账户余额为:" + account.getMoney()); } } }2.2 同步方法synchronized方法控制对对象的的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行。若将一个大的方法声明为synchronized将会影响效率方法里面需要修改的内容才需要锁,锁的太多,浪费资源语法:public synchronized void method(){}示例:public class TestUnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket, "学生").start(); new Thread(buyTicket, "打工人").start(); new Thread(buyTicket, "黄牛党").start(); } } class BuyTicket implements Runnable{ private int ticketNums = 10; boolean flag = true; //外部停止方法 @Override public void run() { //买票 while (flag) { buy(); } } private synchronized void buy(){ //同步方法 //判断是否有票 if (ticketNums <= 0){ flag = false; return; } //模拟延时 try { Thread.sleep(100); //买票 System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--); } catch (InterruptedException e) { e.printStackTrace(); } } }
2021年07月22日
93 阅读
0 评论
0 点赞
2021-07-22
线程的常用方法梳理
1.线程的五大状态创建状态就绪状态阻塞状态运行状态死亡状态2.线程停止不推荐使用jdk提供的stop()、destory()方法。【已废弃】推荐线程自己停止下来建议使用一个标识位进行终止变量示例:/* 测试停止 * 1.建议线程正常停止 * 2.建议使用标识位 * 3.不要使用stop和destroy等过时或者jdk不建议使用的方法 */ public class TestStop implements Runnable{ //1.设置一个标识位 private boolean flag = true; @Override public void run() { int i = 0; while (flag) { System.out.println("线程开始运行" + i++); } } //2.设置一个方法转换标识位 public void stop(){ this.flag = false; } public static void main(String[] args) { TestStop testStop = new TestStop(); new Thread(testStop).start(); for (int i = 0; i < 1000; i++) { System.out.println("主线程开始" + i); if (i == 900) { //调用stop方法切换标识位,使线程停止 testStop.stop(); System.out.println("线程停止了"); } } } }3. 线程休眠_sleepsleep时间指定为当前线程阻塞的毫秒数sleep存在InterruptedException异常sleep时间到时线程进入就绪状态每一个对象都有一把锁,sleep不会释放锁示例1:模拟网络延时public class TestThread2 extends Thread { private int ticketNums=10; @Override public void run() { //重写run()方法 while (true){ if (ticketNums<=0){ break; } //模拟延时 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.getName()+"拿到了第"+ticketNums--+"票"); } } public static void main(String[] args) { //创建Thread子类的实例 TestThread2 testThread = new TestThread2(); //调用start()方法开启线程 testThread.start(); } }示例2:模拟倒计时public class TestSleep { public static void main(String[] args) throws InterruptedException { TestSleep testSleep = new TestSleep(); testSleep.tenDown(); //打印系统时间 Date startTime = new Date(System.currentTimeMillis()); while (true){ try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("yy-MM-dd HH:mm:ss").format(startTime)); startTime = new Date(System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } } //模拟倒计时 public void tenDown() throws InterruptedException { int num = 10; while(true){ Thread.sleep(1000); System.out.println(num--); if (num <= 0) { break; } } } }4.线程礼让_yield礼让线程,让当前正在执行的线程暂停,但不阻塞将线程从运行状态转为就绪状态让cpu重新调度,礼让不一定成功示例://礼让不一定成功,看cpu调度 public class TestYield { public static void main(String[] args) { MyYield myYield = new MyYield(); new Thread(myYield, "a").start(); new Thread(myYield, "b").start(); } } class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + "线程开始执行"); Thread.yield();//礼让 System.out.println(Thread.currentThread().getName() + "线程停止执行"); } }5.线程强制执行_joinjoin合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞可以想象成插队示例://测试join方法(插队) public class TestJoin implements Runnable { public static void main(String[] args) throws InterruptedException { //启动VIP TestJoin testJoin = new TestJoin(); Thread thread = new Thread(testJoin); thread.start(); //main线程 for (int i = 0; i < 1000; i++) { if (i == 200){ thread.join(); } System.out.println("main" + i); } } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("vip来了"); } } }6.获取线程状态_getState线程状态,线程可以处于以下状态之一:NEW 尚未启动的线程处于此状态(创建状态)RUNNABLE 在Java虚拟机中执行的线程处于此状态(运行状态)BLOCKED 被阻塞等待监视器锁定的线程处于此状态(阻塞状态)WAITING 正在等待另一个线程执行特定动作的线程处于此状态(阻塞状态)TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态(阻塞状态)TERMINATED 已退出的线程处于此状态(死亡状态)一个线程可以在给定时间点处于一个状态,这些状态是不反映任何操作系统线程状态的的虚拟机状态示例:public class TestState { public static void main(String[] args) { Thread thread = new Thread(() -> { for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("========"); }); //观察状态 Thread.State state = thread.getState(); System.out.println(state); //new thread.start(); state = thread.getState(); System.out.println(state); while (state != Thread.State.TERMINATED){ //只要线程不停止,就一直运行 try { Thread.sleep(100); state = thread.getState(); System.out.println(state); } catch (InterruptedException e) { e.printStackTrace(); } } } }7.线程的优先级_setPriorityjava提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。线程的优先级用数字表示,范围从1-10Thread.MIN_PRIORITY = 1;Thread.MAX_PRIORITY = 10Thread.NORM_PRIORITY = 5使用getPriority来获取优先级,setPriority来改变优先级优先级高并不一定优先执行,线程的执行顺序真正取决于CPU调度器示例://测试优先级 public class TestPriority{ public static void main(String[] args) { //主线程默认优先级 System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority()); MyPriority myPriority = new MyPriority(); Thread t1 = new Thread(myPriority); Thread t2 = new Thread(myPriority); Thread t3 = new Thread(myPriority); Thread t4 = new Thread(myPriority); //先设置优先级,再启动 t1.start(); t2.setPriority(1); t2.start(); t3.setPriority(4); t3.start(); t4.setPriority(Thread.MAX_PRIORITY); t4.start(); } } class MyPriority extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority()); } }8. 设置守护线程_setDaemon线程分为用户线程和守护线程虚拟机必须确保用户线程执行完毕虚拟机不用等待守护线程如,后台记录操作日志,监控日志,垃圾回收等示例://测试守护线程 public class TestDaemon { public static void main(String[] args) { God god = new God(); You you = new You(); Thread thread = new Thread(god); thread.setDaemon(true); //默认是false,表示是用户线程 thread.start();//守护线程启动 new Thread(you).start();//用户线程启动 } } //上帝 class God implements Runnable { @Override public void run() { while (true) { System.out.println("上帝保佑你"); } } } //你 class You implements Runnable { @Override public void run() { for (int i = 0; i < 36500; i++) { System.out.println("开心的活了100多岁"); } } }
2021年07月22日
175 阅读
0 评论
0 点赞