java同步死锁_Java同步synchronized与死锁

本文详细介绍了Java中解决多线程资源同步问题的两种方式:同步代码块和同步方法。同步代码块通过`synchronized`关键字确保同一时间只有一个线程执行特定代码,而同步方法则将整个方法标记为同步。文中还通过实例展示了如何避免死锁,并解释了静态方法和非静态方法的同步差异。同时,提供了线程间通信的示例,演示了如何通过共享标志位来控制线程执行顺序。
摘要由CSDN通过智能技术生成

多个线程要操作同一资源时就有可能出现资源的同步问题。

同步就是指多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行。

解决资源共享的同步操作,可以使用同步代码块和同步方法两种方式完成。

<1>同步代码块

所谓代码块就是指使用“{}"括起来的一段代码,根据其位置和声明的不同,可以分为普通代码块、构造块、静态块3种,如果在代码块上加上synchronized关键字,则此代码块就称为同步代码块。

ec49198f953064b8580996f838e0eee3.png

package java_thread;

//=================================================

// File Name :Runnable_demo2

//------------------------------------------------------------------------------

// Author :Common

// 类名:MyThread_2

// 属性:

// 方法:

class MyThread_2 implements Runnable{

private int ticket = 5;

@Override

public void run() {//覆写Thread类中的run()方法

// TODO 自动生成的方法存根

for (int i=0;i<10;i++){

synchronized (this) {//设置需要同步的操作

if(ticket>0){

try{

Thread.sleep(300);

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("卖票:ticket="+ticket--);

}

}

//this.sale();//调用同步方法

}

}

}

//主类

//Function : Thread_demo2

public class Runnable_demo2 {

public static void main(String[] args) {

// TODO 自动生成的方法存根

MyThread_2 mt = new MyThread_2();//实例化Runnable子类对象

Thread t1 = new Thread(mt);//实例化Thread类对象

Thread t2 = new Thread(mt);//实例化Thread类对象

Thread t3 = new Thread(mt);//实例化Thread类对象

t1.start();//启动线程

t2.start();//启动线程

t3.start();//启动线程

}

}

98eeaf918a452ce6ee1098f312343ab0.png

package java_thread;

class Output{

public void output(String name){

int len = name.length();

synchronized(this){//不能使用name,因为“输出1”和"输出2"两个字符串不是同一个对象

for(int i=0;i

System.out.print(name.charAt(i));

}

System.out.println();

}

}

}

public class Huchi {

private void init(){

final Output outputer = new Output();

//线程1

new Thread(new Runnable(){

@Override

public void run() {//覆写Thread类中的run()方法

while(true){

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO 自动生成的 catch 块

e.printStackTrace();

}

//new Output().output("输出1");//也不能new对象,new对象的话,this就不代表同一个对象了

outputer.output("输出1");

}

}

}).start();

//线程2

new Thread(new Runnable(){

@Override

public void run() {//覆写Thread类中的run()方法

while(true){

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO 自动生成的 catch 块

e.printStackTrace();

}

//new Output().output("输出1");//也不能new对象,new对象的话,this就不代表同一个对象了

outputer.output("输出2");

}

}

}).start();

}

public static void main(String[] args) {

// TODO 自动生成的方法存根

new Huchi().init();

}

}

43356fa50392f6e6b2535ff6f2142a5e.png

<2>同步方法

也可以使用synchronized关键字将一个方法声明成同步方法

//=================================================

// File Name :Thread_demo

//------------------------------------------------------------------------------

// Author :Common

// 接口名:MyThread

// 属性:

// 方法:

class MyThread_2 implements Runnable{

private int ticket = 5;

@Override

public void run() {//覆写Thread类中的run()方法

// TODO 自动生成的方法存根

for (int i=0;i<10;i++){

this.sale();//调用同步方法

}

}

public synchronized void sale(){//声明同步方法

if(ticket>0){

try{

Thread.sleep(300);

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println("卖票:ticket="+ticket--);

}

}

}

//主类

//Function : Thread_demo2

public class Runnable_demo2 {

public static void main(String[] args) {

// TODO 自动生成的方法存根

MyThread_2 mt = new MyThread_2();//实例化Runnable子类对象

Thread t1 = new Thread(mt);//实例化Thread类对象

Thread t2 = new Thread(mt);//实例化Thread类对象

Thread t3 = new Thread(mt);//实例化Thread类对象

t1.start();//启动线程

t2.start();//启动线程

t3.start();//启动线程

}

}

死锁就是指两个线程都在等待彼此先完成,造成了程序的停滞,一般程序的死锁都是在程序运行时出现的。

多个线程共享同一资源时需要进行同步,以保证资源操作的完整性,但是过多的同步就有可能产生死锁。

生产者不断生产,消费者不断取走生产者生产的产品

//=================================================

// File Name :ThreadInfo_demo

//------------------------------------------------------------------------------

// Author :Common

// 类名:Info

// 属性:

// 方法:

class Info{

private String name = "张三";

private String content = "学生";

private boolean flag = false;

public synchronized void set(String name,String content){//设置信息名称及内容

if(!flag){//标志位为false,不可以生产,在这里等待取走

try{

super.wait();//等待消费者取走

}catch(InterruptedException e){

e.printStackTrace();

}

}

this.setName(name);//设置信息名称

try{

Thread.sleep(300);//加入延迟

}catch(InterruptedException e){

e.printStackTrace();

}

this.setContent(content);//设置信息内容

flag = false;//标志位为true,表示可以取走

super.notify();//唤醒等待线程

}

public synchronized void get(){//取得信息内容

if(flag){//标志位为true,不可以取走

try{

super.wait();//等待生产者生产

}catch(InterruptedException e){

e.printStackTrace();

}

}

try {

Thread.sleep(300);//加入延迟

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(this.getName()+"-->"+this.getContent());//输出信息

flag = true;//修改标志位为true,表示可以生产

super.notify();//唤醒等待线程

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getContent() {

return content;

}

public void setContent(String content) {

this.content = content;

}

}

//类名:Producer

//属性:

//方法:

class Producer implements Runnable{//定义生产者线程

private Info info = null;//保存Info引用

public Producer(Info info) {//构造函数

super();

this.info = info;

}

@Override

public void run() {

// TODO 自动生成的方法存根

boolean flag = false;

for(int i=0;i<50;i++){//50次反复修改name和content的值

if(flag){

this.info.set("张三", "学生");

flag = false;

}else{

this.info.set("李四", "老师");

flag = true;

}

}

}

}

//类名:Consumer

//属性:

//方法:

class Consumer implements Runnable{//定义生产者线程

private Info info = null;//保存Info引用

public Consumer(Info info) {//构造函数

super();

this.info = info;

}

@Override

public void run() {

// TODO 自动生成的方法存根

for(int i=0;i<50;i++){//50次反复修改name和content的值

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

this.info.get();

}

}

}

//主类

//Function : ThreadInfo_demo

public class ThreadInfo_demo {

public static void main(String[] args) {

// TODO 自动生成的方法存根

Info i = new Info();

Producer pro = new Producer(i);

Consumer con = new Consumer(i);

new Thread(pro).start();

new Thread(con).start();

}

}

停止线程运行

在多线程的开发中可以通过设置标志位的方式停止一个线程的运行

//=================================================

// File Name :ThreadInfo_demo

//------------------------------------------------------------------------------

// Author :Common

// 类名:MYThread

// 属性:

// 方法:

class MYThread implements Runnable{

private boolean flag = true;//定义标志位属性

@Override

public void run() {

// TODO 自动生成的方法存根

int i = 0;

while(this.flag){//循环输出

while(true){

System.out.println(Thread.currentThread().getName()+(i++));//输出当前线程名称

}

}

}

public void stop(){//编写停止方法

this.flag = false;//修改标志位

}

}

//主类

//Function : ThreadStop_demo

public class ThreadStop_demo {

public static void main(String[] args) {

// TODO 自动生成的方法存根

MYThread my = new MYThread();

Thread t = new Thread(my,"线程");

t.start();

my.stop();

}

}

互斥性

output1和output2两段代码互斥,检查的都是outputer这个对象

package java_thread;

class Output{

public void output(String name){

int len = name.length();

synchronized(this){//不能使用name,因为“输出1”和"输出2"两个字符串不是同一个对象

for(int i=0;i

System.out.print(name.charAt(i));

}

System.out.println();

}

}

public synchronized void output2(String name){//output1和output2两段代码互斥,检查的都是outputer这个对象

int len = name.length();

for(int i=0;i

System.out.print(name.charAt(i));

}

System.out.println();

}

}

public class Huchi {

private void init(){

final Output outputer = new Output();

//线程1

new Thread(new Runnable(){

@Override

public void run() {//覆写Thread类中的run()方法

while(true){

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO 自动生成的 catch 块

e.printStackTrace();

}

//new Output().output("输出1");//也不能new对象,new对象的话,this就不代表同一个对象了

outputer.output("输出1");

}

}

}).start();

//线程2

new Thread(new Runnable(){

@Override

public void run() {//覆写Thread类中的run()方法

while(true){

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO 自动生成的 catch 块

e.printStackTrace();

}

//new Output().output("输出1");//也不能new对象,new对象的话,this就不代表同一个对象了

outputer.output2("输出2");

}

}

}).start();

}

public static void main(String[] args) {

// TODO 自动生成的方法存根

new Huchi().init();

}

}

faed97a9563724f49cfe7832a86ec547.png

static静态方法调用的对象是字节码对象,所以要把output1的this改成Output.class

package java_thread;

class Output{

public void output1(String name){

int len = name.length();

synchronized(this){//不能使用name,因为“输出1”和"输出2"两个字符串不是同一个对象

for(int i=0;i

System.out.print(name.charAt(i));

}

System.out.println();

}

}

//static静态方法调用的对象是字节码对象,所以要把output1的this改成Output.class

public static synchronized void output3(String name){//output1和output3不同步,除非把output1的this改成Output.class

int len = name.length();

for(int i=0;i

System.out.print(name.charAt(i));

}

System.out.println();

}

}

public class Huchi {

private void init(){

final Output outputer = new Output();

//线程1

new Thread(new Runnable(){

@Override

public void run() {//覆写Thread类中的run()方法

while(true){

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO 自动生成的 catch 块

e.printStackTrace();

}

//new Output().output("输出1");//也不能new对象,new对象的话,this就不代表同一个对象了

outputer.output1("输出1");

}

}

}).start();

//线程2

new Thread(new Runnable(){

@Override

public void run() {//覆写Thread类中的run()方法

while(true){

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO 自动生成的 catch 块

e.printStackTrace();

}

//new Output().output("输出1");//也不能new对象,new对象的话,this就不代表同一个对象了

outputer.output3("输出2");

}

}

}).start();

}

public static void main(String[] args) {

// TODO 自动生成的方法存根

new Huchi().init();

}

}

this      Output.class

16805340da3bd8a6343e837e39699588.png    

9d98af42cfdcccbade26cfedc91f6b8f.png

面试题:子线程循环 10 次,接着主线程循环 100,接着又回到子线程循环 10 次,接着再回到主线程又循环 100,如此循环50 次,请写出程序

package java_thread;

import java.util.concurrent.atomic.AtomicInteger;

//张孝祥java面试题28

//子线程循环 10 次,接着主线程循环 100,接着又回到子线程循环 10 次,接着再回到主线程又循环 100,如此循环50 次,请写出程序

public class TraditionalThreadCommunication {

/**

* @param args

*/

public static void main(String[] args) {

final Business business = new Business();

new Thread(

new Runnable() {

@Override

public void run() {

for(int i=1;i<=50;i++){

business.sub(i);

}

}

}

).start();

for(int i=1;i<=50;i++){

business.main(i);

}

}

}

class Business {

private boolean bShouldSub = true;

public synchronized void sub(int i){

while(!bShouldSub){

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

for(int j=1;j<=10;j++){

System.out.println("sub thread sequence of " + j + ",loop of " + i);

}

bShouldSub = false;

this.notify();

}

public synchronized void main(int i){

while(bShouldSub){

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

for(int j=1;j<=100;j++){

System.out.println("main thread sequence of " + j + ",loop of " + i);

}

bShouldSub = true;

this.notify();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值