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

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

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

<1>同步代码块

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

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(); //启动线程
} }

package java_thread;

class Output{
public void output(String name){
int len = name.length();
synchronized(this){ //不能使用name,因为“输出1”和"输出2"两个字符串不是同一个对象
for(int i=0;i<len;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();
} }

<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<len;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<len;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();
} }

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<len;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<len;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

    

面试题:子线程循环 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();
}
}

Java同步synchronized与死锁的更多相关文章

  1. java同步synchronized

    java同步synchronized volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性. 看下面的这段代码: /** * * @author InJavaWeTrust * */ ...

  2. 转:Java同步synchronized使用

    原文链接 作者:Jakob Jenkov Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(s ...

  3. java 同步 synchronized

    http://www.cnblogs.com/Qian123/p/5691705.html http://www.cnblogs.com/GnagWang/archive/2011/02/27/196 ...

  4. Java的synchronized关键字:同步机制总结

    JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块.搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程 ...

  5. 015-线程同步-synchronized几种加锁方式、Java对象头和Monitor、Mutex Lock、JDK1.6对synchronized锁的优化实现

    一.synchronized概述基本使用 为确保共享变量不会出现并发问题,通常会对修改共享变量的代码块用synchronized加锁,确保同一时刻只有一个线程在修改共享变量,从而避免并发问题. syn ...

  6. Java同步机制总结--synchronized

    不久前用到了同步,现在回过头来对JAVA中的同步做个总结,以对前段时间工作的总结和自我技术的条理话.JAVA中synchronized关键字能够 作为函数的修饰符,也可作为函数内的语句,也就是平时说的 ...

  7. Java多线程-同步:synchronized 和线程通信:生产者消费者模式

    大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...

  8. Java多线程同步 synchronized 关键字的使用

    代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D)运行完这个方法后再运行此线程A, ...

  9. java:同步和死锁

    多个线程共享一个资源的时候需要进行同步(否则会出现错误:如负数,重复数),但是过多的同步会造成死锁. synchronized(this) { } 非同步情况: public class SyncTh ...

随机推荐

  1. 第七章 java基础类库

    1. 日期时间: 用Calendar类. 2. 分隔符:空格.tab.回车. 3. Scanner:读取键盘输入.读取文件. 4. 系统类: System  Runtime. 5. 所有的java类都 ...

  2. git介绍

    简介:Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目.Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件.Git ...

  3. 如何配置全世界最小的 MySQL 服务器

    配置全世界最小的 MySQL 服务器——如何在一块 Intel Edison 为控制板上安装一个 MySQL 服务器. 介绍 在我最近的一篇博文中,物联网,消息以及 MySQL,我展示了如果 Part ...

  4. PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)

    通过curl_setopt()函数可以方便快捷的抓取网页(采集很方便),curl_setopt 是php的一个扩展库 使用条件:需要在php.ini 中配置开启.(PHP 4 >= 4.0.2) ...

  5. 【BZOJ 1096】【ZJOI 2007】仓库建设 DP+斜率优化

    后缀自动机看不懂啊QAQ 放弃了还是看点更有用的东西吧,比如斜率优化DP 先水一道 #include<cstdio> #include<cstring> #include< ...

  6. 做WEB开发的时候,前端与后端我们应该要注意哪些细节,哪些容易出现的漏洞?

    写这篇文章的时候,我和团队正在处理项目漏洞问题,发现这些都是细节但又容易在项目实现的过程中忽视的部分,鉴于此,我想总结下来,方便以后出现类似问题能及时得到解决. 1.任意文件上传漏洞.   描述:允许 ...

  7. Java反射机制详解

    Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反 ...

  8. iOS正则表达式

    //包含数字和字母的密码长度6-16位 -(BOOL) validatePassword:(NSString *)password { //密码正则表达式 NSString *passwordRege ...

  9. hadoop-MapReduce分布式计算框架

    计算框架: MapReduce:主要用于离线计算 Storm:流式计算框架,更适合做实时计算 stack:内存计算框架,快速计算 MapReduce设计理念: --何为分布式计算 --移动计算,而不是 ...

  10. 研究dotnet动态语言IronPython(对应Java的Groovy)

    Java的标配动态语言Groovy,两者搭配可以说是完美!大规模运用的项目,如:Jenkins,通过动态语言可以弥补先天系统缺陷的bug,再者就是加强自己的业务逻辑等. 那么换过dotnet上,对应的 ...