java多线程相关学习笔记
优先级
先设置优先级在启动,不一定一定会优先级高先跑,只能说有效果
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,"a");
Thread t2 = new Thread(myPriority,"b");
Thread t3 = new Thread(myPriority,"c");
Thread t4 = new Thread(myPriority,"d");
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);//最大为10
t4.start();
}
}
class MyPriority implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
守护线程
daemon thread
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕 main
虚拟机不用等待守护线程执行完毕 gc线程垃圾回收线程
package com.zihan.thread;
//测试守护线程
//上帝保佑你
public class DaemonThread{
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(new You()).start();
}
}
class God implements Runnable{
@Override
public void run() {
while(true){
System.out.println("god bless you");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你好好活着吧");
}
System.out.println("=====good bye======");
}
}
线程同步机制
一个资源多个程序同时用就有可能发生问题
解决方法即,让他们排队使用
线程同步其实就是一个等待机制
队列跟锁
每个对象都有一把锁,sleep不会释放锁
synchronized
锁会引起的问题:
一个线程持有锁会导致其他需要此锁的线程挂起;
性能倒置问题
TMD 想清楚什么叫他妈的多个线程操作同一对象
取钱不安全例子
public class kuangshen_unsafebank {
public static void main(String[] args) {
Account account = new Account("结婚基金",100);
Bank2 you = new Bank2(account,50,"you");
Bank2 wife = new Bank2(account,100,"wife");
you.start();
wife.start();
}
}
class Account{
String name;
int balance;
public Account(String name,int balance){
this.name = name;
this.balance = balance;
}
}
class Bank2 extends Thread{
Account account;
int drawingmoney;
int nowMoney;
public Bank2(Account account,int drawingmoney,String name){
super(name);//调用父类方法,即thread方法,来给thread命名。
this.account = account;
this.drawingmoney = drawingmoney;
}
@Override
public void run() {
if(account.balance<drawingmoney){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.balance -= drawingmoney;
nowMoney += drawingmoney;
System.out.println(account.name+"余额为"+account.balance);
//Thread.currentThread().getName() = this.getName(),因为继承了,thread.currentthread本身即为this
System.out.println(this.getName()+"手里的钱是"+nowMoney);
}
}
线程不安全例子
import java.util.ArrayList;
public class arraylistnotsafe {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
线程同步synchronized
会被修改的内容才上锁,只读一般不锁
常见不安全实例
-
//一个多线程的不安全示范代码,本代码目标是从3个窗口购买总共一百张火车票 public class SellTicket implements Runnable{ public static void main(String[] args) { //以下代码是错误示范,因为只需构造一个SellTicket,实例化三个导致有3个100张票 SellTicket window1 = new SellTicket(); SellTicket window2 = new SellTicket(); SellTicket window3 = new SellTicket(); Thread t1 = new Thread(window1,"window1"); Thread t2 = new Thread(window2,"window2"); Thread t3 = new Thread(window3,"window3"); t1.start(); t2.start(); t3.start(); } private int ticket = 100; @Override public void run() { while(ticket>0) { ticket--; System.out.println("从窗口"+Thread.currentThread().getName()+"买了一张票,还剩"+ticket); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } -
修改后的代码,但仍不安全,多线程同时修改变量,会出问题,添加sleep后问题变得更明显,相同票卖了多张,注释懒得改了,如果在ticket--前加sleep,甚至会多次出现负票等情况
package com.zihan.thread_wangyi.Sell_Ticket; //一个多线程的不安全示范代码,本代码目标是从3个窗口购买总共一百张火车票 public class SellTicket implements Runnable{ public static void main(String[] args) { //以下代码是错误示范,因为只需构造一个SellTicket,实例化三个导致有3个100张票 SellTicket window1 = new SellTicket(); Thread t1 = new Thread(window1,"window1"); Thread t2 = new Thread(window1,"window2"); Thread t3 = new Thread(window1,"window3"); t1.start(); t2.start(); t3.start(); } private int ticket = 100; @Override public void run() { while(ticket>0) { ticket--; System.out.println("从窗口"+Thread.currentThread().getName()+"买了一张票,还剩"+ticket); // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } } } }
同步代码块
synchronized(对象){
critical section;
}
解决问题
package com.zihan.thread_wangyi.Sell_Ticket;
//一个多线程的不安全示范代码,本代码目标是从3个窗口购买总共一百张火车票
public class SellTicket implements Runnable{
public static void main(String[] args) {
//以下代码是错误示范,因为只需构造一个SellTicket,实例化三个导致有3个100张票
SellTicket window1 = new SellTicket();
Thread t1 = new Thread(window1,"window1");
Thread t2 = new Thread(window1,"window2");
Thread t3 = new Thread(window1,"window3");
t1.start();
t2.start();
t3.start();
}
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
synchronized (obj){
while(ticket>0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
System.out.println("从窗口"+Thread.currentThread().getName()+"买了一张票,还剩"+ticket);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
同步方法
同步方法锁的是this
带static锁的是.class反射会讲
package com.zihan.thread_wangyi.demo2;
public class Sellticket implements Runnable {
public static void main(String[] args) {
Sellticket sellticket= new Sellticket();
Thread t1 = new Thread(sellticket,"window1");
Thread t2 = new Thread(sellticket,"window2");
t1.start();
t2.start();
}
private int ticket = 100;
@Override
public void run() {
while(true){
if(Thread.currentThread().getName().equals("window1")){
if(SynchronizedMethod()){
break;
}
}
if(Thread.currentThread().getName().equals("window2")){
synchronized (this){
if(ticket<=0){
break;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
System.out.println("从窗口"+Thread.currentThread().getName()+"买了一张票,还剩"+ticket);
}
}
}
}
private synchronized boolean SynchronizedMethod() {
if(ticket<=0){
return true;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
System.out.println("从窗口"+Thread.currentThread().getName()+"买了一张票,还剩"+ticket);
return false;
}
}
lock锁
lock() 获得锁
unlock()释放锁
lock是接口,可以采用实现类Reentranlock来将其实例化
由于下方案例懒得重写,直接复制一开始错误案例,所以当一个线程进入后得到锁后会一直将所有票拿完然后解锁,最后只有一个窗口买了100张票,想要修改,我认为只需改成while(true),然后上锁,然后用if判断票是否卖完,卖完break,没卖完接着卖,然后再解锁。
用lock注意点是解锁要在finally块内,防止中断后,锁没解开。
package com.zihan.thread_wangyi.lock锁;
import java.util.concurrent.locks.ReentrantLock;
//一个多线程的不安全示范代码,本代码目标是从3个窗口购买总共一百张火车票
public class SellTicket implements Runnable{
public static void main(String[] args) {
//以下代码是错误示范,因为只需构造一个SellTicket,实例化三个导致有3个100张票
SellTicket window1 = new SellTicket();
Thread t1 = new Thread(window1,"window1");
Thread t2 = new Thread(window1,"window2");
Thread t3 = new Thread(window1,"window3");
t1.start();
t2.start();
t3.start();
}
private int ticket = 100;
ReentrantLock reentrantLock =new ReentrantLock();
@Override
public void run() {
try{
reentrantLock.lock();
while(ticket>0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
System.out.println("从窗口"+Thread.currentThread().getName()+"买了一张票,还剩"+ticket);
}
}catch (Exception e) {
e.printStackTrace();
}finally {
reentrantLock.unlock();
}
}
}
浙公网安备 33010602011771号