当前位置:首页 » 编程语言 » java同步线程

java同步线程

发布时间: 2022-10-03 01:42:26

‘壹’ java中线程同步方法有哪些

JAVA中线程同步方法一般有以下三种:
1 wait方法:
该方法属于Object的方法,wait方法的作用是使得当前调用wait方法所在部分(代码块)的线程停止执行,并释放当前获得的调用wait所在的代码块的锁,并在其他线程调用notify或者notifyAll方法时恢复到竞争锁状态(一旦获得锁就恢复执行)。
调用wait方法需要注意几点:
第一点:wait被调用的时候必须在拥有锁(即synchronized修饰的)的代码块中。
第二点:恢复执行后,从wait的下一条语句开始执行,因而wait方法总是应当在while循环中调用,以免出现恢复执行后继续执行的条件不满足却继续执行的情况。
第三点:若wait方法参数中带时间,则除了notify和notifyAll被调用能激活处于wait状态(等待状态)的线程进入锁竞争外,在其他线程中interrupt它或者参数时间到了之后,该线程也将被激活到竞争状态。
第四点:wait方法被调用的线程必须获得之前执行到wait时释放掉的锁重新获得才能够恢复执行。
2 notify方法和notifyAll方法:
notify方法通知调用了wait方法,但是尚未激活的一个线程进入线程调度队列(即进入锁竞争),注意不是立即执行。并且具体是哪一个线程不能保证。另外一点就是被唤醒的这个线程一定是在等待wait所释放的锁。
notifyAll方法则唤醒所有调用了wait方法,尚未激活的进程进入竞争队列。
3 synchronized关键字:
第一点:synchronized用来标识一个普通方法时,表示一个线程要执行该方法,必须取得该方法所在的对象的锁。
第二点:synchronized用来标识一个静态方法时,表示一个线程要执行该方法,必须获得该方法所在的类的类锁。
第三点:synchronized修饰一个代码块。类似这样:synchronized(obj) { //code.... }。表示一个线程要执行该代码块,必须获得obj的锁。这样做的目的是减小锁的粒度,保证当不同块所需的锁不冲突时不用对整个对象加锁。利用零长度的byte数组对象做obj非常经济。

‘贰’ Java线程同步,是什么意思

一种是方法前加sychronized
public void sychronized start() {
System.out.println("start");
}

另一种是在代码段之前加sychronized
(sychronized){
。。。。。
}

同步方法(synchronized关键字修饰的方法)可以较好地解决并发问题,在一定程度上可以避免出现资源抢占、竞争条件和死锁的情况,但其副作用是同步锁可导致线程阻塞。这要求同步方法的执行时间不能太长。

这就是所谓的锁机制,你何以使用sychronized(Object obj)锁住某个对象,等你使用完这个对象之后,再进行锁的释放,其他需要该对象的线程才可以执行。

‘叁’ 昆明Java培训:java语言中线程同步的方法有哪些

答:wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

‘肆’ java线程同步问题

首先,你如果要线程同步的话,那么需要用关键字去定义。你如果不去定义让线程同步的话,那么线程永远都是串行的,因为每个时间片段只会执行一部分

Java线程:线程的同步-同步方法

线程的同步是保证多线程安全访问竞争资源的一种手段。
线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源、什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些原则问题需要考虑,是否有竞争资源被同时改动的问题?

在本文之前,请参阅《Java线程:线程的同步与锁》,本文是在此基础上所写的。

对于同步,在具体的Java代码中需要完成一下两个操作:
把竞争访问的资源标识为private;
同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。
当然这不是唯一控制并发安全的途径。

synchronized关键字使用说明
synchronized只能标记非抽象的方法,不能标识成员变量。

为了演示同步方法的使用,构建了一个信用卡账户,起初信用额为100w,然后模拟透支、存款等多个操作。显然银行账户User对象是个竞争资源,而多个并发操作的是账户方法oper(int x),当然应该在此方法上加上同步,并将账户的余额设为私有变量,禁止直接访问。

/**
* Java线程:线程的同步
*
* @author leimin 2009-11-4 11:23:32
*/
public class Test {
public static void main(String[] args) {
User u = new User("张三", 100);
MyThread t1 = new MyThread("线程A", u, 20);
MyThread t2 = new MyThread("线程B", u, -60);
MyThread t3 = new MyThread("线程C", u, -80);
MyThread t4 = new MyThread("线程D", u, -30);
MyThread t5 = new MyThread("线程E", u, 32);
MyThread t6 = new MyThread("线程F", u, 21);

t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}

class MyThread extends Thread {
private User u;
private int y = 0;

MyThread(String name, User u, int y) {
super(name);
this.u = u;
this.y = y;
}

public void run() {
u.oper(y);
}
}

class User {
private String code;
private int cash;

User(String code, int cash) {
this.code = code;
this.cash = cash;
}

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

/**
* 业务方法
* @param x 添加x万元
*/
public synchronized void oper(int x) {
try {
Thread.sleep(10L);
this.cash += x;
System.out.println(Thread.currentThread().getName() + "运行结束,增加“" + x + "”,当前用户账户余额为:" + cash);
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

@Override
public String toString() {
return "User{" +
"code='" + code + '\'' +
", cash=" + cash +
'}';
}
}

输出结果:
线程A运行结束,增加“20”,当前用户账户余额为:120
线程F运行结束,增加“21”,当前用户账户余额为:141
线程E运行结束,增加“32”,当前用户账户余额为:173
线程C运行结束,增加“-80”,当前用户账户余额为:93
线程B运行结束,增加“-60”,当前用户账户余额为:33
线程D运行结束,增加“-30”,当前用户账户余额为:3

Process finished with exit code 0

反面教材,不同步的情况,也就是去掉oper(int x)方法的synchronized修饰符,然后运行程序,结果如下:
线程A运行结束,增加“20”,当前用户账户余额为:61
线程D运行结束,增加“-30”,当前用户账户余额为:63
线程B运行结束,增加“-60”,当前用户账户余额为:3
线程F运行结束,增加“21”,当前用户账户余额为:61
线程E运行结束,增加“32”,当前用户账户余额为:93
线程C运行结束,增加“-80”,当前用户账户余额为:61

Process finished with exit code 0

很显然,上面的结果是错误的,导致错误的原因是多个线程并发访问了竞争资源u,并对u的属性做了改动。

可见同步的重要性。

注意:
通过前文可知,线程退出同步方法时将释放掉方法所属对象的锁,但还应该注意的是,同步方法中还可以使用特定的方法对线程进行调度。这些方法来自于java.lang.Object类。

void notify()
唤醒在此对象监视器上等待的单个线程。
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
void wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
void wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

‘伍’ Java类的实例化顺序是什么样的Java线程同步的方式有哪些

引言:java是在1990年初 ,被詹姆斯•高斯林等人开发的一门面向对象的编程语言。起初,java被称为0ak,来经过发展0ak改名为java,与1995年的五月份正式向大家发布。

一、java类的实例化顺序

java的实例化顺序在继承没有的情况

单独一个类的场景下,初始化顺序为依次为静态数据,继承的基类的构造函数,成员变量,被调用的构造函数。

其中静态数据只会初始化一次。(静态数据包括静态代码块和静态变量,每个类的静态数据只会初始化一次)

在继承的情况下

添加两个基类,让继承父亲,父亲继承祖父。

继承的情况就比较复杂了。由继承了基类,还将往上回溯,递归地调用基类的无参构造方法。

在我们的例子中,在初始化静态数据后,会先往上追溯,调用父的默认构造方法,此时再往上追溯到爷爷的默认构造方法。


无论是java还是什么别的东西他都体现了现代社会与信息技术的不断发展,人们在进行进行技术开发时也有了越来越多的方法。程序类的工作也有了更为快捷的方法,这为信息技术的发展也提供了更好的发展方法

‘陆’ java多线程有几种实现方法,都是什么同步有几种实现方法,都是什么

java中多线程的实现方法有两种:1.直接继承thread类;2.实现runnable接口;同步的实现方法有五种:1.同步方法;2.同步代码块;3.使用特殊域变量(volatile)实现线程同步;4.使用重入锁实现线程同步;5.使用局部变量实现线程同步

其中多线程实现过程中需注意重写或者覆盖run()方法,而对于同步的实现方法中使用较常使用的是利用synchronized编写同步方法和代码块。

‘柒’ java多线程有几种实现方法线程之间如何同步

一、为什么要线程同步

因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常。举个例子,如果一个银行账户同时被两个线程操作,一个取100块,一个存钱100块。假设账户原本有0块,如果取钱线程和存钱线程同时发生,会出现什么结果呢?取钱不成功,账户余额是100.取钱成功了,账户余额是0.那到底是哪个呢?很难说清楚。因此多线程同步就是要解决这个问题。

二、不同步时的代码

Bank.Java

packagethreadTest;

/**
*@authorww
*
*/
publicclassBank{

privateintcount=0;//账户余额

//存钱
publicvoidaddMoney(intmoney){
count+=money;
System.out.println(System.currentTimeMillis()+"存进:"+money);
}

//取钱
publicvoidsubMoney(intmoney){
if(count-money<0){
System.out.println("余额不足");
return;
}
count-=money;
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查询
publicvoidlookMoney(){
System.out.println("账户余额:"+count);
}
}

SyncThreadTest.java


packagethreadTest;


publicclassSyncThreadTest{

publicstaticvoidmain(Stringargs[]){
finalBankbank=newBank();

Threadtadd=newThread(newRunnable(){

@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
while(true){
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
bank.addMoney(100);
bank.lookMoney();
System.out.println(" ");

}
}
});

Threadtsub=newThread(newRunnable(){

@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
while(true){
bank.subMoney(100);
bank.lookMoney();
System.out.println(" ");
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
});
tsub.start();

tadd.start();
}



}

余额不足
账户余额:0


余额不足
账户余额:100


1441790503354存进:100
账户余额:100


1441790504354存进:100
账户余额:100


1441790504354取出:100
账户余额:100


1441790505355存进:100
账户余额:100


1441790505355取出:100
账户余额:100

三、使用同步时的代码

(1)同步方法:


即有synchronized关键字修饰的方法。由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

修改后的Bank.java


packagethreadTest;

/**
*@authorww
*
*/
publicclassBank{

privateintcount=0;//账户余额

//存钱
(intmoney){
count+=money;
System.out.println(System.currentTimeMillis()+"存进:"+money);
}

//取钱
(intmoney){
if(count-money<0){
System.out.println("余额不足");
return;
}
count-=money;
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查询
publicvoidlookMoney(){
System.out.println("账户余额:"+count);
}
}

再看看运行结果:


余额不足
账户余额:0


余额不足
账户余额:0


1441790837380存进:100
账户余额:100


1441790838380取出:100
账户余额:0
1441790838380存进:100
账户余额:100
1441790839381取出:100
账户余额:0

瞬间感觉可以理解了吧。


注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类

(2)同步代码块

即有synchronized关键字修饰的语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步

Bank.java代码如下:


packagethreadTest;

/**
*@authorww
*
*/
publicclassBank{

privateintcount=0;//账户余额

//存钱
publicvoidaddMoney(intmoney){

synchronized(this){
count+=money;
}
System.out.println(System.currentTimeMillis()+"存进:"+money);
}

//取钱
publicvoidsubMoney(intmoney){

synchronized(this){
if(count-money<0){
System.out.println("余额不足");
return;
}
count-=money;
}
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查询
publicvoidlookMoney(){
System.out.println("账户余额:"+count);
}
}

运行结果如下:

余额不足
账户余额:0


1441791806699存进:100
账户余额:100


1441791806700取出:100
账户余额:0


1441791807699存进:100
账户余额:100

效果和方法一差不多。

注:同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。

(3)使用特殊域变量(volatile)实现线程同步


a.volatile关键字为域变量的访问提供了一种免锁机制
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量

Bank.java代码如下:


packagethreadTest;

/**
*@authorww
*
*/
publicclassBank{

privatevolatileintcount=0;//账户余额

//存钱
publicvoidaddMoney(intmoney){

count+=money;
System.out.println(System.currentTimeMillis()+"存进:"+money);
}

//取钱
publicvoidsubMoney(intmoney){

if(count-money<0){
System.out.println("余额不足");
return;
}
count-=money;
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查询
publicvoidlookMoney(){
System.out.println("账户余额:"+count);
}
}

运行效果怎样呢?


余额不足
账户余额:0


余额不足
账户余额:100


1441792010959存进:100
账户余额:100


1441792011960取出:100
账户余额:0


1441792011961存进:100
账户余额:100

是不是又看不懂了,又乱了。这是为什么呢?就是因为volatile不能保证原子操作导致的,因此volatile不能代替synchronized。此外volatile会组织编译器对代码优化,因此能不使用它就不适用它吧。它的原理是每次要线程要访问volatile修饰的变量时都是从内存中读取,而不是存缓存当中读取,因此每个线程访问到的变量值都是一样的。这样就保证了同步。


(4)使用重入锁实现线程同步

在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
ReenreantLock类的常用方法有:
ReentrantLock() : 创建一个ReentrantLock实例
lock() : 获得锁
unlock() : 释放锁
注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用
Bank.java代码修改如下:


packagethreadTest;

importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;

/**
*@authorww
*
*/
publicclassBank{

privateintcount=0;//账户余额

//需要声明这个锁
privateLocklock=newReentrantLock();

//存钱
publicvoidaddMoney(intmoney){
lock.lock();//上锁
try{
count+=money;
System.out.println(System.currentTimeMillis()+"存进:"+money);

}finally{
lock.unlock();//解锁
}
}

//取钱
publicvoidsubMoney(intmoney){
lock.lock();
try{

if(count-money<0){
System.out.println("余额不足");
return;
}
count-=money;
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}finally{
lock.unlock();
}
}

//查询
publicvoidlookMoney(){
System.out.println("账户余额:"+count);
}
}

运行效果怎么样呢?


余额不足
账户余额:0


余额不足
账户余额:0


1441792891934存进:100
账户余额:100


1441792892935存进:100
账户余额:200


1441792892954取出:100
账户余额:100

效果和前两种方法差不多。


如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码 。如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁

(5)使用局部变量实现线程同步


Bank.java代码如下:


packagethreadTest;


/**
*@authorww
*
*/
publicclassBank{

privatestaticThreadLocal<Integer>count=newThreadLocal<Integer>(){

@Override
protectedIntegerinitialValue(){
//TODOAuto-generatedmethodstub
return0;
}

};


//存钱
publicvoidaddMoney(intmoney){
count.set(count.get()+money);
System.out.println(System.currentTimeMillis()+"存进:"+money);

}

//取钱
publicvoidsubMoney(intmoney){
if(count.get()-money<0){
System.out.println("余额不足");
return;
}
count.set(count.get()-money);
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查询
publicvoidlookMoney(){
System.out.println("账户余额:"+count.get());
}
}

运行效果:


余额不足
账户余额:0


余额不足
账户余额:0


1441794247939存进:100
账户余额:100


余额不足
1441794248940存进:100
账户余额:0


账户余额:200


余额不足
账户余额:0


1441794249941存进:100
账户余额:300

看了运行效果,一开始一头雾水,怎么只让存,不让取啊?看看ThreadLocal的原理:


如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。现在明白了吧,原来每个线程运行的都是一个副本,也就是说存钱和取钱是两个账户,知识名字相同而已。所以就会发生上面的效果。


ThreadLocal与同步机制
a.ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题

b.前者采用以"空间换时间"的方法,后者采用以"时间换空间"的方式

‘捌’ Java 线程同步几种方式

(1)同步方法:
即有synchronized关键字修饰的方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
(2)同步代码块
即有synchronized关键字修饰的语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
(3)使用特殊域变量(Volatile)实现线程同步
a.volatile关键字为域变量的访问提供了一种免锁机制
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量
(4)使用重入锁实现线程同步
在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
(5)使用局部变量实现线程同步

热点内容
安卓上哪里下大型游戏 发布:2024-12-23 15:10:58 浏览:189
明日之后目前适用于什么配置 发布:2024-12-23 14:56:09 浏览:56
php全角半角 发布:2024-12-23 14:55:17 浏览:829
手机上传助手 发布:2024-12-23 14:55:14 浏览:733
什么样的主机配置吃鸡开全效 发布:2024-12-23 14:55:13 浏览:831
安卓我的世界114版本有什么 发布:2024-12-23 14:42:17 浏览:711
vbox源码 发布:2024-12-23 14:41:32 浏览:279
诗经是怎么存储 发布:2024-12-23 14:41:29 浏览:661
屏蔽视频广告脚本 发布:2024-12-23 14:41:24 浏览:420
php解析pdf 发布:2024-12-23 14:40:01 浏览:820