问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

JAVA 线程多运行3次???

发布网友 发布时间:2023-11-09 06:21

我来回答

2个回答

热心网友 时间:2024-11-26 15:02

synchronized的作用
一、同步方法
public synchronized void methodAAA(){

//….

}
锁定的是调用这个同步方法的对象

测试:
a、不使用这个关键字修饰方法,两个线程调用同一个对象的这个方法。
目标类:

1public class TestThread {
2 public void execute(){ //synchronized,未修饰
3 for(int i=0;i<100;i++){
4 System.out.println(i);
5 }
6 }
7}

线程类:

1public class ThreadA implements Runnable{
2 TestThread test=null;
3 public ThreadA(TestThread pTest){ //对象有外部引入,这样保证是同一个对象
4 test=pTest;
5 }
6 public void run() {
7 test.execute();
8 }
9}
调用:
1TestThread test=new TestThread();
2Runnable runabble=new ThreadA(test);
3Thread a=new Thread(runabble,"A");
4a.start();
5Thread b=new Thread(runabble,"B");
6b.start();

结果:
输出的数字交错在一起。说明不是同步的,两个方法在不同的线程中是异步调用的。

b、修改目标类,增加synchronized修饰

1public class TestThread {
2 public synchronized void execute(){ //synchronized修饰
3 for(int i=0;i<100;i++){
4 System.out.println(i);
5 }
6 }
7}

结果:
输出的数字是有序的,首先输出A的数字,然后是B,说明是同步的,虽然是不同的线程,但两个方法是同步调用的。
注意:上面虽然是两个不同的线程,但是是同一个实例对象。下面使用不同的实例对象进行测试。

c、每个线程都有独立的TestThread对象。
目标类:

1public class TestThread {
2 public synchronized void execute(){ //synchronized修饰
3 for(int i=0;i<100;i++){
4 System.out.println(i);
5 }
6 }
7}
线程类:
1public class ThreadA implements Runnable{
2 public void run() {
3 TestThread test=new TestThread();
4 test.execute();
5 }
6}
7
调用:
1Runnable runabble=new ThreadA();
2Thread a=new Thread(runabble,"A");
3a.start();
4Thread b=new Thread(runabble,"B");
5b.start();

结果:
输出的数字交错在一起。说明虽然增加了synchronized 关键字来修饰方法,但是不同的线程调用各自的对象实例,两个方法仍然是异步的。

引申:
对于这种多个实例,要想实现同步即输出的数字是有序并且按线程先后顺序输出,我们可以增加一个静态变量,对它进行加锁(后面将说明锁定的对象)。

修改目标类:

1public class TestThread {
2 private static Object lock=new Object(); //必须是静态的。
3 public void execute(){
4 synchronized(lock){
5 for(int i=0;i<100;i++){
6 System.out.println(i);
7 }
8 }
9 }
10}
二、同步代码块

1public void method(SomeObject so){
2 synchronized(so)
3 //…..
4 }
5}
锁定一个对象,其实锁定的是该对象的引用(object reference)
谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以按上面的代码写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它必须是一个对象)来充当锁(上面的解决方法就是增加了一个状态锁)。

a、锁定一个对象,它不是静态的
private byte[] lock = new byte[0]; // 特殊的instance变量
目标类:

1public class TestThread {
2 private Object lock=new Object();
3 public void execute(){
4 synchronized(lock){ //增加了个锁,锁定了对象lock,在同一个类实例中,是线程安全的,但不同的实例还是不安全的。
5
6因为不同的实例有不同对象锁lock
7 for(int i=0;i<100;i++){
8 System.out.println(i);
9 }
10 }
11 }
12}

其实上面锁定一个方法,等同于下面的:

1public void execute(){
2 synchronized(this){ //同步的是当然对象
3 for(int i=0;i<100;i++){
4 System.out.println(i);
5 }
6 }
7}
b、锁定一个对象或方法,它是静态的
这样锁定,它锁定的是对象所属的类
public synchronized static void execute(){
//...
}
等同于

1public class TestThread {
2 public static void execute(){
3 synchronized(TestThread.class){
4 //
5 }
6 }
7}
测试:

目标类:

1public class TestThread {
2 private static Object lock=new Object();
3 public synchronized static void execute(){ //同步静态方法
4 for(int i=0;i<100;i++){
5 System.out.println(i);
6 }
7 }
8 public static void execute1(){
9 for(int i=0;i<100;i++){
10 System.out.println(i);
11 }
12 }
13 public void test(){
14 execute(); //输出是有序的,说明是同步的
15 //execute1(); //输出是无须的,说明是异步的
16 }
17}
线程类:调用不同的方法,于是建立了两个线程类

1public class ThreadA implements Runnable{
2 public void run() {
3 TestThread.execute();//调用同步静态方法
4 }
5}
6public class ThreadB implements Runnable{
7 public void run() {
8 TestThread test=new TestThread();
9 test.test();//调用非同步非静态方法
10 }
11}
调用:

1Runnable runabbleA=new ThreadA();
2Thread a=new Thread(runabbleA,"A");
3a.start();
4Runnable runabbleB=new ThreadB();
5Thread b=new Thread(runabbleB,"B");
6b.start();
注意:
1、用synchronized 来锁定一个对象的时候,如果这个对象在锁定代码段中被修改了,则这个锁也就消失了。看下面的实例:

目标类:

1public class TestThread {
2 private static final class TestThreadHolder {
3 private static TestThread theSingleton = new TestThread();
4 public static TestThread getSingleton() {
5 return theSingleton;
6 }
7 private TestThreadHolder() {
8 }
9 }
10
11 private Vector ve =null;
12 private Object lock=new Object();
13 private TestThread(){
14 ve=new Vector();
15 initialize();
16 }
17 public static TestThread getInstance(){
18 return TestThreadHolder.getSingleton();
19 }
20 private void initialize(){
21 for(int i=0;i<100;i++){
22 ve.add(String.valueOf(i));
23 }
24 }
25 public void reload(){
26 synchronized(lock){
27 ve=null;
28 ve=new Vector();
29 //lock="abc";
30 for(int i=0;i<100;i++){
31 ve.add(String.valueOf(i));
32 }
33 }
34 System.out.println("reload end");
35 }
36
37 public boolean checkValid(String str){
38 synchronized(lock){
39 System.out.println(ve.size());
40 return ve.contains(str);
41 }
42 }
43}
说明:在reload和checkValid方法中都增加了synchronized关键字,对lock对象进行加锁。在不同线程中对同一个对象实例分别调用reload和checkValid方法。
在reload方法中,不修改lock对象即注释lock="abc"; ,结果在控制台输出reload end后才输出100。说明是同步调用的。
如果在reload方法中修改lock对象即去掉注释,结果首先输出了一个数字(当前ve的大小),然后输出reload end。说明是异步调用的。

2、单例模式中对多线程的考虑

1public class TestThread {
2 private static final class TestThreadHolder {
3 private static TestThread theSingleton = new TestThread();
4 public static TestThread getSingleton() {
5 return theSingleton;
6 }
7 private TestThreadHolder() {
8 }
9 }
10 private Vector ve =null;
11 private Object lock=new Object();
12 private TestThread(){
13 ve=new Vector();
14 initialize();
15 }
16 public static TestThread getInstance(){
17 return TestThreadHolder.getSingleton();
18 }
19 '''
20}
说明:增加了一个内部类,在内部类中申明一个静态的对象,实例化该单例类,初始化的数据都在单例类的构造函数中进行。这样保证了多个实例同时访问的时候,初始化的数据都已经成功初始化了。

总结:
A. 无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁,所以首先应知道需要加锁的对象
B.每个对象只有一个锁(lock)与之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

热心网友 时间:2024-11-26 15:03

因为你的代码是线程不安全的,你可以到网上找找java线程同步的相关文章。如下代码就不会有重复的输出了:
public class Thd3 {
public static void main(String[] args){
Sell s=new Sell();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
new Thread(s).start();
}
}
class Sell implements Runnable{
int i=100;
public synchronized void run(){
while(i>0){
System.out.println(Thread.currentThread().getName()+"___"+i);
i--;
}
}
}
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
在线条形码生成 ie地址栏是什么 ie浏览器的官网地址是什么? 团餐定制电话 抖音电商与广东商务厅启动“富域计划” 简单的晚餐晒美食文案句子 简单的晚餐晒美食说说短句 鸭肉炒什么好吃家常做法 为什么越背越记不住 绯牡丹锦多久浇水 绯牡丹养护要点 solidworks中的“IsFastener,PunchI... What size is it?这什么意思? 我一个手机号注册了两个,另外一个登不上了,怎么办? 一个号码注册了两个 怎么找回第一个? 成人高考应该考学位英语还是四级英语? 大哥 天津的恒天财富怎么样 待遇和发展前景 明天叫我去面试 ... 迹部景吾是谁?56 找工作进工银安盛好还是进平安好呢 求专业的意见 倩女幽魂截至目前还可以领那些礼包 求激活码 一个手机号注册了两个前一个怎么办 倩女幽魂现在还有哪些礼包可以领取? 84年对越自卫反击战牺牲的战士抚恤金城镇与农村有多大区别 被封禁了,怎么办啊? 北京现代瑞纳油箱容量是多少122 请问有人加盟南京食全食美公司的古茗吗? 叛逆期孩子管不住,有地方可以管教的吗?1 八十年代带薪上学算工龄吗 怎么改第二次? 身份证后面的x怎么添加微信红包,手机上面没有大小写! 映泰(BIOSTAR) Hi-Fi B85S3 主板有4个内... 马可到底结婚了没有啊?153 康熙儿子都是怎么死的37 改过一次怎么改第二次? 修改一年内如何二次修改吗苹果 一年内怎么改第二次 JAVA 线程多运行3次??? 小孩做骨折手术后心率达到240是什么原因 英国模特:Model is 188cm&#47;6&#39;2&quot; and w... 我是学体育的,体育分和文化课分需要多少才能进铜陵学院? 心跳过快有时达到240多次每分钟 ...现在在莆田、请问从莆田去东莞清晰坐大巴要多少车费 、要坐几小时... 演《暖春》得小女孩是谁?就是那个小花!4 一年内能改第二次吗? 想去诚信保险公司做,还是中国平安好 有谁了解工银安盛人寿保险怎么样?以及中国保险行业的未来是怎么... 谁知道多少各种香料的用途?8 恒天财富的投资顾问怎么样,有发展前途吗? 几种常见的披萨饼香料(西餐香料香草)7 成考学位英语和英语四级有区别吗? 一张身份证绑定两个一个能用零钱支付一个不能用怎么回事?