-
多线程的两种实现方法?实现线程同步的方法?
2011-10-10 22:38:09答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口 同步的实现方面有两种,分别是synchronized,wait与notify答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
同步的实现方面有两种,分别是synchronized,wait与notify
-
Java的两种线程同步方法
2020-06-08 10:54:48Java的两种线程同步方法基本概念synchronizedLocksynchronized与Lock对比 基本概念 当多个线程同时操作一个可共享的资源时会出现线程安全问题,将会导致数据不一致,因此使用同步锁来防止该操作执行完之前不许被其他...Java的两种线程同步方法
基本概念
当多个线程同时操作一个可共享的资源时会出现线程安全问题,将会导致数据不一致,因此使用同步锁来防止该操作执行完之前不许被其他线程执行,从而保证了该变量的唯一性和准确性。使用synchronized和使用Lock是两种Java常用的实现线程同步方法。
synchronized
(1)介绍
使用synchronized关键字,可以修饰普通方法、静态方法,以及语句块。由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。需要注意的是调用静态方法时,锁住的不是对象,锁住的是类。//修饰普通方法 public synchronized void function1(){ } //修饰语句块 synchronized(object){ } //修饰静态方法 public static synchronized int function2(){ }
同步是一种高开销的操作,因此应该尽量减少同步的内容。 通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。
(2)同步方法示例代码
这里以三个人同时买票为例,加上synchronized关键字,使买票的方法buy()成为同步方法,防止多个人抢到同一张票:public class TicketTest { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); //同时启动三个线程买票 new Thread(buyTicket, "Jason").start(); new Thread(buyTicket, "Flash").start(); new Thread(buyTicket, "Lucy").start(); } } class BuyTicket implements Runnable { private int ticketNum = 100; boolean flag = true;//外部停止方式 @Override public void run() { while(flag) { try { buy(); Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } //加上synchronized使buy()成为同步方法 private synchronized void buy() throws InterruptedException { if(ticketNum <= 0) { flag = false; return; } Thread.sleep(10); System.out.println(Thread.currentThread().getName()+"拿到第"+ticketNum--+"张票"); } }
Lock
(1)介绍
- 从JDK5.0开始,Java提供了更强大的线程同步机制——通过显示定义同步锁对象来实现同步,同步锁使用Lock对象充当。
- java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
- ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显示加锁、释放锁。
(2)示例代码
这里定义了一把ReentrantLock,将加锁和解锁操作放在try语句中,保证解锁操作一定会执行。import java.util.concurrent.locks.ReentrantLock;//导入包 public class TicketTest2 { public static void main(String[] args) { BuyTicket2 buyTicket = new BuyTicket2(); new Thread(buyTicket, "Jason").start(); new Thread(buyTicket, "Flash").start(); new Thread(buyTicket, "Lucy").start(); } } class BuyTicket2 implements Runnable { private int ticketNum = 100; boolean flag = true;//外部停止方式 private final ReentrantLock lock = new ReentrantLock();//定义lock锁 @Override public void run() { while(flag) { try { try { lock.lock();//加锁 buy(); } finally{ lock.unlock();//解锁 } Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } private void buy() throws InterruptedException { if(ticketNum <= 0) { flag = false; return; } Thread.sleep(10); System.out.println(Thread.currentThread().getName()+"拿到第"+ticketNum--+"张票"); } }
synchronized与Lock对比
- Lock是显示锁(手动开启和关闭锁),synchronized是隐式锁,出了作用域自动释放。
- Lock只有代码块锁,synchronized有代码块锁和方法锁。
- 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好,并且具有更好的扩展性(提供更多的子类)。
-
Day64.线程的生命周期、线程同步的两种方法实现 -Java多线程
2020-10-07 20:48:49线程同步的两种方法实现 方式一: 同步代码块 方式一: 同步代码块 使用实现Runnable接口的方式 /** * 创建三个窗口,总票数为100张,使用实现Runnable接口的方式 * 存在线程安全问题,待解决。 * * 1. 卖票...线程的生命周期
线程同步的两种方法实现
方式一: 同步代码块
方式一: 同步代码块 使用实现Runnable接口的方式 /** * 创建三个窗口,总票数为100张,使用实现Runnable接口的方式 * 存在线程安全问题,待解决。 * * 1. 卖票过程中,出现了重票、错票 --->线程安全问题 * 2. 问题出现的原因: 当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也来操作车票。 * 3. 如何解决: 当一个线程在操作ticket的时候,其他线程不能参与进来。直到线程A操作完ticket时 * 其他线程才可以开始操作ticket。这种情况即是线程A出现了阻塞,也不能被改变。 * 4. 在Java中,我们通过同步机制,来解决线程的安全问题。 * * 方式一: 同步代码块 * * synchronized(同步监视器){ * //需要被同步的代码 * * } * 说明: 1. 操作共享数据的代码,即为需要被同步的代码 -->不能包含代码多了,也不能包含代码少了。 * 2. 共享数据: 多个线程共同操作的变量。比如: ticket就是共享数据 * 3. 同步监视器,俗称: 锁。任何一个类的对象,都可以充当锁。 * 要求: 多个线程必须要共用同一个把锁。 * * 补充: 在实现Runnable接口创建多线程的方式中,我们可以考虑,使用this充当同步监视器。 * * * 方拾二: 同步方法 * * 5. 同步的方式,解决了线程的安全问题。 --->好处 * 操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。 --->局限性 * * @author 阿昌 * @create 2020-10-07 11:27 */ class WThread implements Runnable { private int ticket = 100; Object obj = new Object(); @Override public void run() { while (true) { synchronized (this) { //synchronized (obj) { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 卖票,票号为: " + ticket); ticket--; } else { break; } } } } public static class WindowTest1 { public static void main(String[] args) { WThread wThread = new WThread(); Thread t1 = new Thread(wThread); Thread t2 = new Thread(wThread); Thread t3 = new Thread(wThread); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } } }
方式一: 同步代码块 使用继承Thread类的方式实现 /**例子: * 创建三个窗口,总票数为100张,使用继承Thread类的方式实现 * * 存在线程安全问题,待解决。 * ↓ ↓ ↓ ↓ ↓ ↓ * 使用同步代码块来解决继承Thread类的方式的线程安全问题 * * 说明: 在继承Thread类创建多线程的方式中,慎用this充当同步监视器。考虑使用当前类充当同步监视器。 * * @author 阿昌 * @create 2020-10-07 10:09 */ class Window extends Thread{ private static int ticket = 100; static Object obj =new Object(); @Override public void run() { while (true){ //错误的方式: this代表的t1,t2,t3三个对象 //synchronized(this){ //正确的 // synchronized(obj){ synchronized(Window.class){ //Class clazz = Window.class;Window.class只会加载一次 if (ticket> 0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + ": 买票,票号为: "+ ticket); ticket--; }else{ System.out.println(getName() + "票已售空"); break; } } } } } public class WindowTest { public static void main(String[] args) { Window w1 = new Window(); Window w2 = new Window(); Window w3 = new Window(); w1.setName("窗口1"); w2.setName("窗口2"); w3.setName("窗口3"); w1.start(); w2.start(); w3.start(); } }
方式二: 同步方法
方式二: 同步方法 实现Runnable接口 /** * 使用 同步方法 解决实现Runnable接口的线程安全问题 * * 关于同步方法的总结: * 1. 同步方法仍然涉及到同步监视器,只是不需要我们显示的声明。 * 2. 非静态的同步方法,同步监视器是: this * 静态的同步方法,同步监视器是: 当前类本身 * * * @author 阿昌 * @create 2020-10-07 19:10 */ class WThread2 implements Runnable { private int ticket = 100; @Override public void run() { while (ticket > 0) { show(); } } private synchronized void show(){// 同步监视器: this if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 卖票,票号为: " + ticket); ticket--; } } } public class WindowTest2 { public static void main(String[] args) { WThread2 wThread2 = new WThread2(); Thread t1 = new Thread(wThread2); Thread t2 = new Thread(wThread2); Thread t3 = new Thread(wThread2); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } }
方式二: 同步方法 继承Thread类 /** * 使用 同步方法 来解决继承Thread类实现多线程安全问题 * @author 阿昌 * @create 2020-10-07 19:48 */ class Window3 extends Thread{ private static int ticket = 100; @Override public void run() { while (true){ show(); } } private static synchronized void show(){//同步监视器: Window3.class //private synchronized void show(){//同步监视器:this: w1,w2,w3。此种解决方法是错误的 if (ticket> 0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ": 买票,票号为: "+ ticket); ticket--; } } } public class WindowTest3 { public static void main(String[] args) { Window3 w1 = new Window3(); Window3 w2 = new Window3(); Window3 w3 = new Window3(); w1.setName("窗口1"); w2.setName("窗口2"); w3.setName("窗口3"); w1.start(); w2.start(); w3.start(); } }
-
实现线程同步的几种方法
2018-09-27 09:50:52因此引入多线程同步,也就是说多个线程只能一个对共享的资源进行更改,其他线程不能对数据进行修改。 如下一个两个线程对一个银行账户进行存钱的小实例,其中使用synchornized修饰方法实现线程的同步 代码如下: `...- 在多线程程序中,会出现多个线程抢占一个资源的情况,这时间有可能会造成冲突,也就是一个线程可能还没来得及将更改的 资源保存,另一个线程的更改就开始了。可能造成数据不一致。因此引入多线程同步,也就是说多个线程只能一个对共享的资源进行更改,其他线程不能对数据进行修改。
- 1.如下一个两个线程对一个银行账户进行存钱的小实例,其中使用synchornized修饰方法实现线程的同步
- 代码如下:
class bank{ private int count=100; public synchronized void dispit() { count+=10; } public int getcount() { return count; } } class ThreadCount extends Thread{ private bank count; private JTextArea textarea = new JTextArea(); public ThreadCount(bank count,JTextArea textarea) { this.count = count; this.textarea = textarea; } public void run() { for(int i=0; i<10; i++) { count.dispit(); textarea.append("账户余额为:"+count.getcount()+"\n"); } } }
2.同步是一种高开销的操作,因此应该尽量减少同步内容,因此也可以使用修饰代码块来代替修饰整个方法。
class bank{ private int count=100; public void dispit() { synchronized(this) { count+=10; } } public int getcount() { return count; } } class ThreadCount extends Thread{ private bank count; private JTextArea textarea = new JTextArea(); public ThreadCount(bank count,JTextArea textarea) { this.count = count; this.textarea = textarea; } public void run() { for(int i=0; i<10; i++) { count.dispit(); textarea.append("账户余额为:"+count.getcount()+"\n"); } } }
3.使用volatile修饰数据,对于当下问题,只用使用volatile来修饰账户的余额变量即可。该修饰词是对域变量的访问提供了以这种防锁机制,相当于告诉虚拟机,该域的变量可能被更改。因此每次使用该域都要重新计算,而不是从寄存器中取出数据。从而实现线程的同步。该修饰词不能修改final类型变量
class bank{ private volatile int count=100; public void dispit() { count+=10; } public int getcount() { return count; } } class ThreadCount extends Thread{ private bank count; private JTextArea textarea = new JTextArea(); public ThreadCount(bank count,JTextArea textarea) { this.count = count; this.textarea = textarea; } public void run() { for(int i=0; i<10; i++) { count.dispit(); textarea.append("账户余额为:"+count.getcount()+"\n"); } } }
4.使用重入锁实现线程同步。使用类ReentrantLock类来定义锁,其中lock()方法为打开锁,unlock()方法为关闭锁
类似于synchronized修饰方法有一样功能。使用锁时间需要注意应该及时放开锁,不然会进入死锁状态。一般是在finally中释放锁class bank{ private volatile int count=100; private Lock lock = new ReentrantLock(); public void dispit() { lock.lock(); try { count+=10; }finally{ lock.unlock(); } } public int getcount() { return count; } } class ThreadCount extends Thread{ private bank count; private JTextArea textarea = new JTextArea(); public ThreadCount(bank count,JTextArea textarea) { this.count = count; this.textarea = textarea; } public void run() { for(int i=0; i<10; i++) { count.dispit(); textarea.append("账户余额为:"+count.getcount()+"\n"); } } }
代码的输出结果如下:
可以看到,每次增加10 的时间只有一个线程在进行,也就是线程的同步5.使用ThreadLocal类来管理。不过该方法和同步机制不相同。该类管理的变量在每个线程中都有自己的副本,副本之间相互独立,因此获得的结果和其他不同。
class bank{ private static ThreadLocal<Integer> count = new ThreadLocal() { protected Integer initialValue() { return 100; } }; private Lock lock = new ReentrantLock(); public void dispit() { lock.lock(); try { count.set(count.get()+10); }finally{ lock.unlock(); } } public int getcount() { return count.get(); } } class ThreadCount extends Thread{ private bank count; private JTextArea textarea = new JTextArea(); public ThreadCount(bank count,JTextArea textarea) { this.count = count; this.textarea = textarea; } public void run() { for(int i=0; i<10; i++) { count.dispit(); textarea.append("账户余额为:"+count.getcount()+"\n"); } } }
结果如图:
可以看到,在改程序中,好比两个账户相互独立,互不干扰一样。同样解决了相同的变量访问冲突问题。 -
多线程同步的实现方法
2019-08-21 18:46:21两种用法: synchronized方法: public synchronized void mutiThreadAccess(); synchronized代码块: synchronized(syncObject) { //访问syncObject的代码 } 2、wait()方法和notify()方法 3、Lock lock(): 以... -
线程同步方法 java_Java如何实现线程同步?线程同步的方法和反面教材
2021-02-27 09:56:59Java线程同步是保证多线程状态下安全访问竞争资源的一种编程手段,但线程的同步在Java多线程编程中算是一个比较难的难点,很多开发者甚至都不知道什么是竞争资源,也不知道时候需要进行线程同步,当然这是没有明确... -
线程通讯和同步的两种实现方法
2016-05-08 22:37:00同步有两种方法实现,一种是利用synchronized标示,另外一种是加锁。 生成锁的对象的方法是:private static Lock lock = new ReentrantLock();Lock是一个接口,而Reentrantlock是一个实现的类。构造方法有:... -
多线程同步的实现方法有哪些?
2018-12-14 10:39:59个人博客:小景哥哥 Java主要提供了3种实现同步机制: ①synchronized关键字 在Java语言中,每个对象都有一个对象锁与之相关联,该锁表明对象在...synchronized关键字有两种用法,synchronized方法和synchro... -
线程同步的几种实现方法
2016-11-18 11:25:13二、为什么要线程同步 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常。举个例子,如果一个银行账户同时被两个线程... -
多线程实现同步的实现方法
2020-10-08 14:40:30synchronized有两种用法(方法和代码块),还可用于静态方法,实例,类 synchronized方法 当一个方法体规模非常大时,使用同步方法会大大影响程序的执行效率,所以Java提供了同步块。 synchronized块 synchronized -
多线程有几种实现方法,同步有几种实现方法
2020-08-13 18:35:29多线程有两种实现方法:继承 Thread 类或者实现 Runnable 接口。 一.继承 Thread 类 //1、作为Thread的子类,并重写run方法。把多线程的业务写在run方法中 //2、默认实现是super.run(); //3、创建线程对象 //4、开启... -
多线程的几种实现方法?同步的几种实现方法?
2013-09-08 16:06:08同步的实现方面有两种,分别是synchronized,wait与notify wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉... -
实现线程同步的方法
2016-01-22 16:28:02同步的实现方面有两种,分别是synchronized,wait与notify wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉... -
线程有几种实现方法?同步有几种实现方法?
2019-09-25 21:54:20多线程有两种实现方法,分别是继承Thread类与实现Runnable接口 同步的实现方面有两种,分别是synchronized,wait与notify -
多线程的两种实现方式、操作方法、同步与死锁
2020-10-07 19:49:51一、多线程的实现 1、 继承 Thread 类 启动线程步骤: a、定义Thread类的子类(继承Thread类),并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体 b、创建Thread子类的... -
多线程、同步实现方法?
2020-10-15 17:55:331)实现线程有两种方法: 继承 Thread 类或者实现 Runnable 接口 2) 实现同步也有两种,一种是用同步方法,一种是用同步块… 同步方法就是在 方法返回类型后面加上 synchronized, 比如: public void synchronized add... -
Java多线程系列三——实现线程同步的方法
2019-01-21 14:33:56两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 下文用三种不同的方式实现... -
多线程和同步的实现方法
2014-06-12 22:43:00同步的实现方面有两种,分别是synchronized,wait与notify wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉... -
多线程时,线程同步的两种方法简单介绍
2016-11-20 18:29:04在典型的卖票程序中,需要考虑多个窗口买票时的数据同步问题,对此可能需要线程同步,下面简单介绍下两种同步方法; Demo:public static void main(String[] args) { ThickesRunnable tr = new ThickesRunnable()... -
java 线程同步的方法_Java线程原理和5种同步方法
2021-02-28 16:36:58Java线程原理和5种同步方法自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:目录1 Java线程原理和两种实现方式... 11.1 java线程原理和源码解析... 11.2 实现 Runnable 接口实现run方法... ... -
多线程、同步的实现方法
2014-02-13 11:14:00同步的实现方面有两种,分别是synchronized,wait与notify wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉... -
多线程有几种实现方法?同步有几种实现方法?
2019-09-23 17:14:37同步的实现方面有两种,分别是synchronized,wait与notify wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉... -
多线程的实现方法,同步的实现方式
2017-05-15 11:21:11多线程有两种实现方法: 方法一:继承Thread类,重写方法run(); 方法二:实现Runnable接口,实现方法run(); 同步有两种方法: 方法一:用同步方法(在方法返回类型后面加上synchronized); 方法二:用... -
线程的四种实现方式,一些方法及线程的同步
2019-03-21 11:07:00Java多线程实现的方式有四种 1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法,实现Runnable...前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有... -
实现多线程同步的两种方式
2019-11-02 18:41:00为了确保在任何时间点一个共享的资源只能被一个线程使用,使用了“同步”。 一、使用同步方法 package sort; public class Timer { private static int num=0; public synchronized void add(String name){ num+... -
java多线程有几种实现方法?线程之间如何同步
2017-07-08 09:59:33同步的实现方法有五种:1.同步方法;2.同步代码块;3.使用特殊域变量(volatile)实现线程同步;4.使用重入锁实现线程同步;5.使用局部变量实现线程同步 。其中多线程实现过程中需注意重写或者覆盖run()方法,而对于...