并发:同一对象被多个线程同时操作
线程同步:使用队列与锁 问题:优先级倒置、效率下降
synchronized 修饰符
常见数据紊乱情况【多人买票】
package hk.Thread.syn;
public class Deon1 {
public static void main(String[] args) {
Buy buy = new Buy();
new Thread(buy,"p1").start();
new Thread(buy,"p2").start();
new Thread(buy,"p3").start();
}
}
class Buy implements Runnable{
private int sumnums=5;
boolean flag=true;
@Override
public void run() {
while (flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void buy() throws InterruptedException {
if (sumnums<=0){
flag=false;
return;
}
Thread.sleep(500);
System.out.println(Thread.currentThread().getName()+"买到了"+(sumnums--)+"号");
}
}
同步方法
synchronized 关键字放在方法之前,方法变为《同步方法》,锁的是this,创建该方法的类
package hk.Thread.syn;
public class Deon1_1 {
public static void main(String[] args) {
Buy0 buy0 = new Buy0();
new Thread(buy0,"p1").start();
new Thread(buy0,"p2").start();
new Thread(buy0,"p3").start();
}
}
class Buy0 implements Runnable{
private int sumnums=5;
boolean flag=true;
@Override
public void run() {
while (flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private synchronized void buy() throws InterruptedException {
if (sumnums<=0){
flag=false;
return;
}
Thread.sleep(500);
System.out.println(Thread.currentThread().getName()+"买到了"+(sumnums--)+"号");
}
}
此类情况将syncgronized 放在run()方法前锁定的是Draw类【无法防止money数据紊乱】 而需要锁的数据是Account的money
package hk.Thread.syn;
//多个线程对同一个账户取钱
public class Deon2 {
public static void main(String[] args) {
Account 程心 = new Account("程心", 1000);
Draw 线上取钱 = new Draw(程心, 800, "线上取钱");
Draw 线下取钱 = new Draw(程心, 700, "线下取钱");
线上取钱.start();
线下取钱.start();
}
}
//账户
class Account{
int money;
String name;
public Account(String name,int money) {
this.name=name;
this.money=money;
}
}
//取钱
class Draw extends Thread{
Account account;
int drawmoney;
int nowmoney;
Draw(Account account,int drawmoney,String name){
super(name);
this.drawmoney=drawmoney;
this.account=account;
}
//取钱
public synchronized void run(){
if (account.money<drawmoney){
System.out.println(Thread.currentThread().getName()+"——钱不够了");
return;
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money=account.money-drawmoney;
nowmoney+=drawmoney;
System.out.println(account.name+"余额"+account.money);
System.out.println(this.getName()+"现金"+nowmoney);
}
}
同步块
synchronized( 【需要锁的对象、需要增删改查 】 ){
【代码块】
}
package hk.Thread.syn;
//多个线程对同一个账户取钱
public class Deon2 {
public static void main(String[] args) {
Account 程心 = new Account("程心", 1000);
Draw 线上取钱 = new Draw(程心, 800, "线上取钱");
Draw 线下取钱 = new Draw(程心, 700, "线下取钱");
线上取钱.start();
线下取钱.start();
}
}
//账户
class Account{
int money;
String name;
public Account(String name,int money) {
this.name=name;
this.money=money;
}
}
//取钱
class Draw extends Thread{
Account account;
int drawmoney;
int nowmoney;
Draw(Account account,int drawmoney,String name){
super(name);
this.drawmoney=drawmoney;
this.account=account;
}
//取钱
public void run(){
synchronized (account){
if (account.money<drawmoney){
System.out.println(Thread.currentThread().getName()+"——钱不够了");
return;
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money=account.money-drawmoney;
nowmoney+=drawmoney;
System.out.println(account.name+"余额"+account.money);
System.out.println(this.getName()+"现金"+nowmoney);
}
}
}
代码块 的另一个例子 多个线程名字对list同一位置添加
package hk.Thread.syn;
import java.util.ArrayList;
public class Deom3 {
public static void main(String[] args) throws InterruptedException {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(1000);
System.out.println(list.size());
}
}
在实现线程内部使用synchronized
package hk.Thread.syn;
import java.util.ArrayList;
public class Deom3 {
public static void main(String[] args) throws InterruptedException {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
Thread.sleep(1000);
System.out.println(list.size());
}
}
关于死锁 【嵌套使用synchronized】 多个线程的情况;在某个线程获取锁后,该线程需要【另一个线程同样获取锁后的资源】属于两个以上的线程在都处于获取锁后需要对方占用的资源才能释放锁 程序处于无法结束卡死的情况
package hk.Thread.syn;
public class Deon4 {
public static void main(String[] args) {
Text text1 = new Text(0,"p1");
Text text2 = new Text(1,"p2");
text1.start();
text2.start();
}
}
class A{ }
class B{ }
class Text extends Thread{
static A a=new A();
static B b=new B();//使用static修饰符确保a,b唯一性
int choice;
String name;
public Text(int choice,String name) {
this.choice = choice;
this.name = name;
}
@Override
public void run() {
if (choice==0){
synchronized (a){
System.out.println(this.name+"获取了a的锁");
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b){
System.out.println(this.name+"获取了b的锁");
}
}
}else {
synchronized (b){
System.out.println(this.name+"获取了b的锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a){
System.out.println(this.name+"获取了a的锁");
}
}
}
}
}
解决方案 不嵌套使用synchronized
package hk.Thread.syn;
public class Deon4 {
public static void main(String[] args) {
Text text1 = new Text(0,"p1");
Text text2 = new Text(1,"p2");
text1.start();
text2.start();
}
}
class A{ }
class B{ }
class Text extends Thread{
static A a=new A();
static B b=new B();//使用static修饰符确保a,b唯一性
int choice;
String name;
public Text(int choice,String name) {
this.choice = choice;
this.name = name;
}
@Override
public void run() {
if (choice==0){
synchronized (a){
System.out.println(this.name+"获取了a的锁");
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (b){
System.out.println(this.name+"获取了b的锁");
}
}else {
synchronized (b){
System.out.println(this.name+"获取了b的锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (a){
System.out.println(this.name+"获取了a的锁");
}
}
}
}
Lock 锁
定义锁:private final ReentrantLock lock = new ReentrantLock();
lock.lock()上锁 lock.unlock() 解锁
package hk.Thread.syn.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Deon1 {
public static void main(String[] args) {
Text text = new Text();
new Thread(text).start();
new Thread(text).start();
new Thread(text).start();
new Thread(text).start();
}
}
class Text implements Runnable{
int sum=5;
ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
try {
if (sum>0){
System.out.println("买了第"+(sum--)+"个");
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}finally {
lock.unlock();
}
}
}
}
Lock | synchronized |
显式锁 | 隐式锁 |
手动启动锁关闭锁 | 出了作用域自动释放锁 |
性能高 |
优先级:Lock》同步代码块》同步方法