Java 多线程

线程主要通过共享对字段的访问和参考字段引用的对象进行通信。这种通信形式非常有效,但可能出现两种错误:线程干扰和内存一致性错误。需要一些同步构造来防止这些错误。以下示例显示了我们需要同步的情况。

在Java中需要同步的情况

请考虑以下示例:

// Java program to illustrate need

// of Synchronization

import java.io.*;

class Multithread

{

private int i = 0;

public void increment()

{

i++;

}

public int getValue()

{

return i;

}

}

class GfG

{

public static void main (String[] args)

{

Multithread t = new Multithread();

t.increment();

System.out.println(t.getValue());

}

}

输出:

1

在上面的示例中,执行了三个操作:

获取变量i的值。

增加获取的值。

并将增加的i值存储到其位置。

这里,

第一个线程获取i的值。(当前值i为0)并将其增加1,因此变量i的值变为1。

现在第二个线程访问i的值为0,因为第一个线程没有将它存储回它的位置。

第二个线程也会增加它并将其存储回其位置。第1个也存储它。

最后,变量i的值为1.但是两个线程的效果应该是2。这就是为什么我们需要同步对共享变量i的访问。

Java是多线程语言,其中多个线程并行运行以完成其执行。我们需要同步共享资源以确保一次只有一个线程能够访问共享资源。

如果一个Object由多个线程共享,则需要进行同步以避免Object的状态被破坏。当Object是可变的时,需要同步。如果共享Object是不可变的,或者共享同一个Object的所有线程只读取未修改的Object状态,则不需要同步它。

Java编程语言提供两种同步习语:

方法同步

语句同步(块同步)

Java中的方法同步

同步方法支持一种简单的策略来防止线程干扰和内存一致性错误。如果一个Object对多个线程可见,则对该Object的所有字段的读取或写入都是通过synchronized方法完成的。

两次调用同步方法不可能进行交错。如果一个线程正在执行synchronized方法,那么在同一个Object上调用synchronized方法的所有其他线程都必须等到第一个线程完成Object。

示例:这显示了多个线程是否在没有同步的情况下访问getLine()方法。

// Example illustrates multiple threads are executing

// on the same Object at same time without synchronization.

import java.io.*;

class Line

{

// if multiple threads(trains) will try to

// access this unsynchronized method,

// they all will get it. So there is chance

// that Object's  state will be corrupted.

public void getLine()

{

for (int i = 0; i < 3; i++)

{

System.out.println(i);

try

{

Thread.sleep(400);

}

catch (Exception e)

{

System.out.println(e);

}

}

}

}

class Train extends Thread

{

// reference to Line's Object.

Line line;

Train(Line line)

{

this.line = line;

}

@Override

public void run()

{

line.getLine();

}

}

class GFG

{

public static void main(String[] args)

{

// Object of Line class that is shared

// among the threads.

Line obj = new Line();

// creating the threads that are

// sharing the same Object.

Train train1 = new Train(obj);

Train train2 = new Train(obj);

// threads start their execution.

train1.start();

train2.start();

}

}

输出:

0

0

1

1

2

2

可能有两列火车(两个以上)需要同时使用,因此有可能发生碰撞。因此,为了避免碰撞,我们需要同步多个想要运行的行。

示例:对同一对象的getLine()方法的同步访问

// Example that shows multiple threads

// can execute the same method but in

// synchronized way.

class Line

{

// if multiple threads(trains) trying to access

// this synchronized method on the same Object

// but only one thread will be able

// to execute it at a time.

synchronized public void getLine()

{

for (int i = 0; i < 3; i++)

{

System.out.println(i);

try

{

Thread.sleep(400);

}

catch (Exception e)

{

System.out.println(e);

}

}

}

}

class Train extends Thread

{

// Reference variable of type Line.

Line line;

Train(Line line)

{

this.line = line;

}

@Override

public void run()

{

line.getLine();

}

}

class GFG

{

public static void main(String[] args)

{

Line obj = new Line();

// we are creating two threads which share

// same Object.

Train train1 = new Train(obj);

Train train2 = new Train(obj);

// both threads start executing .

train1.start();

train2.start();

}

}

输出:

0

1

2

0

1

2

Java中的块同步

如果我们只需要执行一些后续代码行而不是方法中代码的所有行(指令),那么我们应该只同步存在所需指令的代码块。

例如,假设有一个方法包含100行代码,但只有10行代码(一个接一个)包含代码的关键部分,即这些行可以修改(更改)Object的状态。因此,我们只需要同步这10行代码方法,以避免对Object状态进行任何修改,并确保其他线程可以在同一方法中执行其余行而不会中断。

import java.io.*;

import java.util.*;

public class Geek

{

String name = "";

public int count = 0;

public void geekName(String geek, List list)

{

// Only one thread is permitted

// to change geek's name at a time.

synchronized(this)

{

name = geek;

count++;  // how many threads change geek's name.

}

// All other threads are permitted

// to add geek name into list.

list.add(geek);

}

}

class GFG

{

public static void main (String[] args)

{

Geek gk = new Geek();

List list = new ArrayList();

gk.geekName("mohit", list);

System.out.println(gk.name);

}

}

输出:

1

重点:

当线程进入同步方法或块时,它获取锁定,一旦完成任务并从synchronized方法退出,它就会释放锁定。

当线程进入同步实例方法或块时,它获取对象级别锁定,当它进入同步静态方法或块时,它获取类级别锁定。

如果在synchronized块中使用的Object为null,则Java同步将抛出空指针异常。例如,如果在synchronized(实例)中,instance为null,则它将抛出空指针异常。

在Java中,wait(),notify()和notifyAll()是同步中使用的重要方法。

您不能将java synchronized关键字应用于变量。

不要在同步块上的非final字段上进行同步,因为对非final字段的引用可能随时更改,然后不同的线程可能在不同的对象上同步,即根本不同步。

优点

多线程:由于java是多线程语言,因此同步是实现共享资源互斥的好方法。

实例和静态方法:同步实例方法和同步静态方法都可以同时执行,因为它们用于锁定不同的对象。

限制

并发限制: Java同步不允许并发读取。

降低效率: Java同步方法运行速度非常慢并且会降低性能,因此您应该在绝对必要时同步方法,否则不要同步块仅用于代码的关键部分。

java中同步_在Java中的方法同步和语句同步(块同步) - Break易站相关推荐

  1. java 方法名相同_Java的方法的重载 :方法名相同,参数类型不同 - Break易站

    人类设计语言时,相同的词汇可以表达多种意思.而在Java里面,方法也被设计成这个模式,而区分这些相同方法名的就是方法的参数. Java的方法的重载的特点 方法的重载有下面的特点: 1. 方法名相同,参 ...

  2. java logging包_用JDK中提供的java.util.logging.*包创建Logger对象----原创

    由于项目中用到了Applet与Servlet之间(客户端用Applet.Server端用Servlet)的通信,要求: 1:>客户端与服务端必须出Log. 2:>浏览器在加载Applet时 ...

  3. java coin介绍_代码示例中的Java 7:Project Coin

    java coin介绍 该博客通过代码示例介绍了一些新的Java 7功能,这些项目在Project Coin一词下进行了概述. Project Coin的目标是向JDK 7添加一组小的语言更改.这些更 ...

  4. java 线程状态_浅析Java中的线程状态

    一.线程的5种状态 众所周知,Java的线程状态有5种,分别对应上图中五种不同颜色,下面对这5种状态及状态间的转化做相应的解释: 1. 初始化状态:新建一个线程对象 2. 可运行状态:其他线程调用了该 ...

  5. java递归优化_在Java中谈尾递归--尾递归和垃圾回收的比较

    我不是故意在JAVA中谈尾递归的,因为在JAVA中谈尾递归真的是要绕好几个弯,只是我确实只有JAVA学得比较好,虽然确实C是在学校学过还考了90+,真学得没自学的JAVA好 不过也是因为要绕几个弯,所 ...

  6. java协程_在Java中使用协程(Coroutine)

    各种语言在实现Coroutine方式的支持时,多数都采用了Actor Model来实现,Actor Model简单来说就是每个任务就是一个Actor,Actor之间通过消息传递的方式来进行交互,而不采 ...

  7. java实现分而治之_并发编程中一种经典的分而治之的思想!!

    写在前面 在JDK中,提供了这样一种功能:它能够将复杂的逻辑拆分成一个个简单的逻辑来并行执行,待每个并行执行的逻辑执行完成后,再将各个结果进行汇总,得出最终的结果数据.有点像Hadoop中的MapRe ...

  8. java 的继承_关于java中的继承

    我们都知道Java中的继承是复用代码.扩展子类的一种方式,继承使得Java中重复的代码能够被提取出来供子类共用,对于Java程序的性能以及修改和扩展有很大的意义,所以这是一个非常重要的知识点. 那么对 ...

  9. java final 类_在Java中,final修饰的类有什么特点

    展开全部 关于Java中的32313133353236313431303231363533e4b893e5b19e31333264663736final(2010-09-09 14:19:48)转载▼ ...

最新文章

  1. STM32单片机如何使用JLINK下载
  2. C++Primer第五版——习题答案详解(九)
  3. inconsistent debug frame and source code -Eclipse调试器里看到的代码行数和实际源代码不一致该怎么办
  4. .propertie文件注释
  5. 北京交通大学计算机系2018年录取情况,北京交通大学2018年高招录取分数线汇总...
  6. docker卸载 windows版本_DevOps系列 006 - Docker安装
  7. Hadoop学习笔记(一):零Linux基础安装hadoop过程笔记
  8. 麦马计算机科学 UBC工程,2020年UBC文书题目
  9. 李开复发自前方:From Davos with AI
  10. Linux 命令(140)—— tree 命令
  11. 一些常用网站的总结与分享
  12. docker---dockerfile 编写优化
  13. 过渡属性transition详解
  14. .shtml网站解析UnicodeError
  15. phpstorm配置vcs自动上传代码
  16. 电脑远程登录控制Android手机-Webkey For Android使用教程
  17. 列表最后一页的最后一条数据删除之后,页码自动减一
  18. STRM--用Oracle Streams wizard生成配置脚本
  19. unityui炫酷动画_Unity_Animation实现UI星星闪耀效果①
  20. spring诸如方式_回滚诸如在家工作之类的程序时,请谨慎操作

热门文章

  1. 六耳猕猴并不存在,真假猴王的六耳原来是他!
  2. SQL基础【二十、索引】(超细致版本,前理论,后实践,应对sql面试绰绰有余)
  3. AIX卷管理介绍以及利用空闲PP来创建文件系统
  4. {“errmsg“:“name length invalid rid: 5fbf54ef-3a02c“,“errcode“:300002}
  5. 鸟哥Linux私房菜(基础篇)——第五章:首次登入与在线求助 man page笔记
  6. npm的镜像替换成淘宝
  7. es6笔记 day3---对象简介语法以及对象新增
  8. C# SQLite事务操作方法分析
  9. MySQL下perror工具查看System Error Code信息
  10. 『Linux基础 - 4 』linux常用命令(1)