热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

多线程知识点:同步

*两个储户,到同一个银行存钱,每个人存了3次,一次100元。1,描述银行。2,描述储户任务。分析多线程是

/*
两个储户,到同一个银行存钱,每个人存了3次,一次100元。
1,描述银行。
2,描述储户任务。分析多线程是否存在安全隐患。1,线程任务中是否有共享的数据。
2,是否多条操作共享数据的代码。同步函数。其实就是在函数上加上了同步关键字进行修饰。
同步表现形式有两种:1,同步代码块,2,同步函数。同步函数使用的锁是什么呢?函数需要被对象调用,哪个对象不确定,但是都用this来表示。
同步函数使用的锁就是this。
*/
class Bank
{
private int sum;
// private Object obj = new Object();public synchronized void add(int n){
// synchronized(obj)
// {sum = sum + n;try{Thread.sleep(10);}catch(Exception e){}System.out.println("sum="+sum);
// }
}
}
class Customer implements Runnable
{
private Bank b &#61; new Bank();public void run(){for(int x&#61;0; x<3; x&#43;&#43;){b.add(100);}}
}
class BankDemo
{
public static void main(String[] args) {//1,创建任务对象。Customer c &#61; new Customer();Thread t1 &#61; new Thread(c);Thread t2 &#61; new Thread(c);t1.start();t2.start();}
}

/*
验证同步函数使用的锁是this。验证需求&#xff1a;
启动两个线程。
一个线程负责执行同步代码块(使用明锁)。
另一个线程使用同步函数(使用this锁)。
两个执行的任务是一样的都是卖票。如果他们没有使用相同的锁&#xff0c;说明他们没有同步。会出现数据错误。怎么能让一个线程一直在同步代码块中&#xff0c;一个线程在同步函数呢&#xff1f;
可以通过切换的方式。
*/class SaleTicket implements Runnable
{
private int tickets &#61; 100;//定义一个boolean标记。boolean flag &#61; true;Object obj &#61; new Object();public void run(){if(flag) while(true){synchronized(this){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;"....code....."&#43;tickets--);}}}elsewhile(true)sale();}public synchronized void sale(){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;".....func...."&#43;tickets--);}}
}
class ThisLockDemo
{
public static void main(String[] args) throws InterruptedException{SaleTicket t &#61; new SaleTicket();Thread t1 &#61; new Thread(t);Thread t2 &#61; new Thread(t);t1.start();Thread.sleep(10);t.flag &#61; false;t2.start();}
}

/*
如果同步函数被static修饰呢&#xff1f;static方法随着类加载&#xff0c;这时不一定有该类的对象。但是一定有一个该类的字节码文件对象。
这个对象简单的表示方式就是 类名.class Class
*/class SaleTicket implements Runnable
{
private static int tickets &#61; 100;//定义一个boolean标记。boolean flag &#61; true;Object obj &#61; new Object();public void run(){if(flag) while(true){synchronized(SaleTicket.class){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;"....code....."&#43;tickets--);}}}elsewhile(true)sale();}public static synchronized void sale(){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;".....func...."&#43;tickets--);}}
}
class StaticLockDemo
{
public static void main(String[] args) throws InterruptedException{SaleTicket t &#61; new SaleTicket();Thread t1 &#61; new Thread(t);Thread t2 &#61; new Thread(t);t1.start();Thread.sleep(10);t.flag &#61; false;t2.start();}
}

//饿汉式。相对与多线程并发&#xff0c;安全&#xff01;class Single
{
private static final Single SINGLE_INTSTANCE &#61; new Single();private Single(){}public static Single getInstance(){return SINGLE_INTSTANCE;}
}
//懒汉式。延迟加载模式。
/*

在多线程并发访问时&#xff0c;会出现线程安全问题。
加了同步就可以解决问题。无论是同步函数&#xff0c;还是同步代码块都行。
但是&#xff0c;效率低了。
怎么解决效率低的问题。
可以通过if对单例对象的双重判断的形式。哦耶&#xff01;
*/
class Single
{
private static Single s &#61; null;private Single(){}public static Single getInstance(){if(s&#61;&#61;null){synchronized(Single.class){if(s&#61;&#61;null)//-->0 s &#61; new Single();}}return s;}
}
class Demo implements Runnable
{
public void run(){Single.getInstance();}
}
class ThreadSingleTest
{
public static void main(String[] args) {System.out.println("Hello World!");}
}

/*
同步函数&#xff0c;同步代码块。同步代码块使用的任意的对象作为锁。
同步函数只能使用this作为锁。如果说&#xff1a;一个类中只需要一个锁&#xff0c;这时可以考虑同步函数&#xff0c;使用this&#xff0c;写法简单。
但是&#xff0c;一个类中如果需要多个锁&#xff0c;还有多个类中使用同一个锁&#xff0c;这时只能使用同步代码块。建议使用同步代码块。
*/class
{
public static void main(String[] args) {System.out.println("Hello World!");}
}

/*
死锁&#xff1a;场景一&#xff1a;同步嵌套。
*/class SaleTicket implements Runnable
{
private int tickets &#61; 100;//定义一个boolean标记。boolean flag &#61; true;Object obj &#61; new Object();public void run(){if(flag) while(true){synchronized(obj)//obj lock
{sale();}}elsewhile(true)sale();}public synchronized void sale()//this lock
{synchronized(obj){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;".....func...."&#43;tickets--);}}}
}
class DeadLockDemo
{
public static void main(String[] args) throws InterruptedException{SaleTicket t &#61; new SaleTicket();Thread t1 &#61; new Thread(t);Thread t2 &#61; new Thread(t);t1.start();Thread.sleep(10);t.flag &#61; false;t2.start();}
}

/*
多线程间的通信。多个线程都在处理同一个资源&#xff0c;但是处理的任务却不一样。
生产者&#xff0c;消费者。通过同步&#xff0c;解决了没生产就消费的问题。
*/
//描述资源。
class Res
{
private String name;private int count &#61; 1;//提供了给商品赋值的方法。public synchronized void set(String name){this.name &#61; name &#43; "--" &#43; count;count&#43;&#43;;System.out.println(Thread.currentThread().getName()&#43;"...生产者....."&#43;this.name);}//提供一个获取商品的方法。public synchronized void get(){System.out.println(Thread.currentThread().getName()&#43;".......消费者....."&#43;this.name);}
}
//生成者。
class Producer implements Runnable
{
private Res r;Producer(Res r){this.r &#61; r;}public void run(){while(true)r.set("面包");}
}
//消费者
class Consumer implements Runnable
{
private Res r;Consumer(Res r){this.r &#61; r;}public void run(){ while(true)r.get();}
}
class ProducerConsumerDemo
{
public static void main(String[] args) {//1,创建资源。Res r &#61; new Res();//2&#xff0c;创建两个任务。Producer pro &#61; new Producer(r);Consumer con &#61; new Consumer(r);//3,创建线程。Thread t1 &#61; new Thread(pro);Thread t2 &#61; new Thread(con);t1.start();t2.start();}
}

//同步嵌套&#xff0c;死锁。class Task implements Runnable
{
private boolean flag;Task(boolean flag){this.flag &#61; flag;}public void run(){if(flag){while(true)synchronized(MyLock.LOCKA){System.out.println("if.....locka");synchronized(MyLock.LOCKB){System.out.println("if.....lockb");}}}else{while(true)synchronized(MyLock.LOCKB){System.out.println("else.....lockb");synchronized(MyLock.LOCKA){System.out.println("else.....locka");}}}}
}
class MyLock
{
public static final Object LOCKA &#61; new Object();public static final Object LOCKB &#61; new Object();
}
class DeadLockTest
{
public static void main(String[] args) {//创建线程任务。Task t1 &#61; new Task(true);Task t2 &#61; new Task(false);new Thread(t1).start();new Thread(t2).start();}
}

/*
多线程间的通信。多个线程都在处理同一个资源&#xff0c;但是处理的任务却不一样。
生产者&#xff0c;消费者。通过同步&#xff0c;解决了没生产就消费的问题。但是出现了连续的生产没有消费的情况&#xff0c;和需求生产一个&#xff0c;消费一个的情况不符。使用了等待唤醒机制。
wait():该方法可以让线程处于冻结状态&#xff0c;并将线程临时存储到线程池中。
notify():唤醒指定线程池中的任意一个线程。
notifyAll():唤醒指定线程池中的所以线程。这些方法必须使用在同步中&#xff0c;因为它们用来操作同步锁上的线程的状态的。在使用这些方法时&#xff0c;必须标识它们所属于的锁。标识方式就是 锁对象.wait(); 锁对象.notify(); 锁对象.notifyAll();相同锁的notify()&#xff0c;可以获取相同锁的wait();
*/
//描述资源。
class Res
{
private String name;private int count &#61; 1;//定义标记。private boolean flag;//提供了给商品赋值的方法。public synchronized void set(String name){if(flag)//判断标记为true&#xff0c;执行wait。等待。为false。就生产。try{this.wait();}catch(InterruptedException e){}this.name &#61; name &#43; "--" &#43; count;count&#43;&#43;;System.out.println(Thread.currentThread().getName()&#43;"...生产者....."&#43;this.name);//生成完毕&#xff0c;将标记改为true。flag &#61; true;//唤醒消费者。this.notify();}//提供一个获取商品的方法。public synchronized void get(){if(!flag)try{this.wait();}catch(InterruptedException e){}System.out.println(Thread.currentThread().getName()&#43;".......消费者....."&#43;this.name);//将标记改为false。flag &#61; false;//唤醒生产者。this.notify();}
}
//生成者。
class Producer implements Runnable
{
private Res r;Producer(Res r){this.r &#61; r;}public void run(){while(true)r.set("面包");}
}
//消费者
class Consumer implements Runnable
{
private Res r;Consumer(Res r){this.r &#61; r;}public void run(){ while(true)r.get();}
}
class ProducerConsumerDemo2
{
public static void main(String[] args) {//1,创建资源。Res r &#61; new Res();//2&#xff0c;创建两个任务。Producer pro &#61; new Producer(r);Consumer con &#61; new Consumer(r);//3,创建线程。Thread t1 &#61; new Thread(pro);Thread t2 &#61; new Thread(con);t1.start();t2.start();}
}

/*多生产多消费。问题1&#xff1a;重复生成&#xff0c;重复消费。原因&#xff1a;经过复杂的(等&#xff0c;资格)分析&#xff0c;发现被唤醒的线程没有判断标记就开始工作(生成or消费)了。导致了重复的生成和消费的发生。解决&#xff1a;那就是被唤醒的线程必须判断标记。使用while循环搞定。问题2&#xff1a;死锁了。所有的线程都处于冻结状态。原因&#xff1a;本方线程在唤醒时&#xff0c;又一次唤醒了本方线程。而本方线程循环判断标记&#xff0c;又继续等待。而导致所有的线程都等待了。解决&#xff1b;希望本方如果唤醒了对方线程&#xff0c;就可以解决。可以使用notifyAll()方法。那不是全唤醒了吗&#xff1f;是的。既有本方&#xff0c;又有对方。但是本方醒后&#xff0c;会判断标记继续等待。这样对方就有线程可以执行了。已经实现了多生产多消费。但是有些小问题&#xff0c;效率有点低&#xff0c;因为notifyAll也唤醒了本方。做了不必要的判断。
*///描述资源。
class Res
{
private String name;private int count &#61; 1;//定义标记。private boolean flag;//提供了给商品赋值的方法。public synchronized void set(String name)//
{while(flag)//判断标记为true&#xff0c;执行wait。等待。为false。就生产。try{this.wait();}catch(InterruptedException e){}//t0(等) t1(等)this.name &#61; name &#43; "--" &#43; count;//面包1 &#xff0c;面包2 面包3
count&#43;&#43;;//2 3 4
System.out.println(Thread.currentThread().getName()&#43;"...生产者....."&#43;this.name);//t0 面包1、 t0 面包2 t1 &#xff0c;面包3//生成完毕&#xff0c;将标记改为true。flag &#61; true;//唤醒所有等待线程(包括本方线程)。this.notifyAll();}//提供一个获取商品的方法。public synchronized void get()//
{while(!flag)try{this.wait();}catch(InterruptedException e){}//t2(等) t3(等)System.out.println(Thread.currentThread().getName()&#43;".......消费者....."&#43;this.name);//t2 面包1.//将标记改为false。flag &#61; false;//唤醒所有等待线程(包括本方线程)。this.notifyAll();}
}
//生成者。
class Producer implements Runnable
{
private Res r;Producer(Res r){this.r &#61; r;}public void run(){while(true)r.set("面包");}
}
//消费者
class Consumer implements Runnable
{
private Res r;Consumer(Res r){this.r &#61; r;}public void run(){ while(true)r.get();}
}
class ProducerConsumerDemo3
{
public static void main(String[] args) {//1,创建资源。Res r &#61; new Res();//2&#xff0c;创建两个任务。Producer pro &#61; new Producer(r);Consumer con &#61; new Consumer(r);//3,创建线程。Thread t0 &#61; new Thread(pro);Thread t1 &#61; new Thread(pro);Thread t2 &#61; new Thread(con);Thread t3 &#61; new Thread(con);t0.start();t1.start();t2.start();t3.start();}
}

/*1&#xff0c;搞定妖的问题。2&#xff0c;name和sex是私有的。需要在Res类中对外提供访问name和sex的方法。这个可以参照生产者消费者producerconsumerdemo.java3&#xff0c;实现间隔输出&#xff0c;使用等待唤醒机制。producerconsumerdemo2.java*/class Res
{String name;String sex;
}
class Input implements Runnable
{
private Res r;Input(Res r){this.r &#61; r;}public void run(){int x &#61; 0;while(true){if(x&#61;&#61;0){r.name &#61; "张三";r.sex &#61; "男男男男男男男";}else{r.name &#61; "rose";r.sex &#61; "women";}x &#61; (x&#43;1)%2;}}}class Output implements Runnable
{
private Res r;Output(Res r){this.r &#61; r;}public void run(){while(true){System.out.println(r.name&#43;"...."&#43;r.sex);}}}class Test
{
public static void main(String[] args) {Res r &#61; new Res();Input in &#61; new Input(r);Output out &#61; new Output(r);new Thread(in).start();new Thread(out).start();}
}

 

转:https://www.cnblogs.com/vijay/p/3511261.html



推荐阅读
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 开发日志:201521044091 《Java编程基础》第11周学习心得与总结
    开发日志:201521044091 《Java编程基础》第11周学习心得与总结 ... [详细]
  • 本文是Java并发编程系列的开篇之作,将详细解析Java 1.5及以上版本中提供的并发工具。文章假设读者已经具备同步和易失性关键字的基本知识,重点介绍信号量机制的内部工作原理及其在实际开发中的应用。 ... [详细]
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • Java中不同类型的常量池(字符串常量池、Class常量池和运行时常量池)的对比与关联分析
    在研究Java虚拟机的过程中,笔者发现存在多种类型的常量池,包括字符串常量池、Class常量池和运行时常量池。通过查阅CSDN、博客园等相关资料,对这些常量池的特性、用途及其相互关系进行了详细探讨。本文将深入分析这三种常量池的差异与联系,帮助读者更好地理解Java虚拟机的内部机制。 ... [详细]
  • 深入解析 Android 中 EditText 的 getLayoutParams 方法及其代码应用实例 ... [详细]
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • 本文详细解析了客户端与服务器之间的交互过程,重点介绍了Socket通信机制。IP地址由32位的4个8位二进制数组成,分为网络地址和主机地址两部分。通过使用 `ipconfig /all` 命令,用户可以查看详细的IP配置信息。此外,文章还介绍了如何使用 `ping` 命令测试网络连通性,例如 `ping 127.0.0.1` 可以检测本机网络是否正常。这些技术细节对于理解网络通信的基本原理具有重要意义。 ... [详细]
  • Spring框架中枚举参数的正确使用方法与技巧
    本文详细阐述了在Spring Boot框架中正确使用枚举参数的方法与技巧,旨在帮助开发者更高效地掌握和应用枚举类型的数据传递,适合对Spring Boot感兴趣的读者深入学习。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • POJ 2482 星空中的星星:利用线段树与扫描线算法解决
    在《POJ 2482 星空中的星星》问题中,通过运用线段树和扫描线算法,可以高效地解决星星在窗口内的计数问题。该方法不仅能够快速处理大规模数据,还能确保时间复杂度的最优性,适用于各种复杂的星空模拟场景。 ... [详细]
  • 在Java基础中,私有静态内部类是一种常见的设计模式,主要用于防止外部类的直接调用或实例化。这种内部类仅服务于其所属的外部类,确保了代码的封装性和安全性。通过分析JDK源码,我们可以发现许多常用类中都包含了私有静态内部类,这些内部类虽然功能强大,但其复杂性往往让人感到困惑。本文将深入探讨私有静态内部类的作用、实现方式及其在实际开发中的应用,帮助读者更好地理解和使用这一重要的编程技巧。 ... [详细]
  • 本文探讨了如何利用Java代码获取当前本地操作系统中正在运行的进程列表及其详细信息。通过引入必要的包和类,开发者可以轻松地实现这一功能,为系统监控和管理提供有力支持。示例代码展示了具体实现方法,适用于需要了解系统进程状态的开发人员。 ... [详细]
  • 线程能否先以安全方式获取对象,再进行非安全发布? ... [详细]
author-avatar
2012-蜕变_502
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有