多线程问题

jinger00 2014-07-22 10:38:29
package com.thread.sychronized;

/**
* Created by Vincent on 2014/7/22.
*/
public class TraditionalThreadSychronized {

public static void main(String[] args) {
new TraditionalThreadSychronized().init();
}

private void init() {
final OutPut outPut = new OutPut();
new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outPut.output("tianlongbabu");
}
}
}.start();
new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outPut.output("shediaoyingxiongzhuan");
}
}
}.start();
}

class OutPut {
public void output(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}


output方法写法跟平时大家用的工具类方法一样,为什么会有线程不安全问题呢?如果方法如下写:
   class OutPut {
private String xxx="";
public void output(String name) {
int len = name.length();
synchronized (xxx){
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}

这样为什么会是线程安全的?如果第一个例子不是线程安全的,那这个例子中 字符串长度会随时改变 也会不是线程安全的呢
请高手帮忙释疑,在这里谢谢了

以上例子是看张孝祥多线程视频所想。
...全文
655 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
静山晚风 2014-08-08
  • 打赏
  • 举报
回复
第一个看似不安全,但是运行了半天也没抛异常,楼主是不是出错了,首先 对象不是静态变量,分别起的是独立的类,不同的对象,不同的变量,反正我执行一直没出差,不安全指的是对同一个自由的控制,对非同一资源控制不存在这个问题,改为静态变量在不用同步到情况应该会出现这个问题吧
醉欲眠卿且去 2014-08-08
  • 打赏
  • 举报
回复
线程安全的,如果不安全,那样枷锁也是有问题的
wu244534279 2014-07-28
  • 打赏
  • 举报
回复
引用 21 楼 jinger00 的回复:
引用 19 楼 jinger00 的回复:
引用 16 楼 u010793975 的回复:
没有同一个共享的资源,是线程安全的
那标题那个一个个打印字符的那个例子,也没有共享资源呀 怎么不是线程安全的呢
我这是跟着张孝祥的多线程视频敲得,请赐教哪里有问题呢
确实,你这个程序是模拟线程不安全,而不是真正的线程不安全。 给你写了一个真正线程不安全的例子,你自己运行一下,仔细分析下结果,线程这种东西需要认真细心学才能搞懂,旁人几句话也说不通。
public class ThreadTest {
	private int i = 0;

	public static void main(String[] args) {
		ThreadTest threadTest = new ThreadTest();
		new Thread(threadTest.new MyThread(), "a").start();
		new Thread(threadTest.new MyThread(), "b").start();
	}

	class MyThread implements Runnable {

		@Override
		public void run() {
			while (true) {
				System.out.println("线程" + Thread.currentThread().getName()
						+ "运行中,现在的i值为:" + i);
				try {
					Thread.sleep(1000);//线程读完i后,睡眠1秒钟再对i进行修改,以便分析。
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("线程" + Thread.currentThread().getName()
						+ "运行中,经过++i后,现在的i值为:" + ++i);
			}
		}

	}
}
这个例子中,a、b两条线程都会去读写共享变量i值,现在会可能出现某个时候这样的情况: 线程a把i值读进来了值是0,相当于a.i==0,然后a睡眠1秒; 这时候到b线程开始读,这时候i值还是0,相当于b.i==0,b线程也开始睡眠1秒; 然后是a线程睡眠结束它又开始执行了,这回是++a.i,然后线程a会将a.i的值也就是1传回到类变量i中,这时候类变量i的值为1; 接下来b线程睡眠结束继续执行,这次是++b.i,结果b.i的值是1,然后b线程也将b.i的值传回到类变量i中,这个时候类变量i的值还是1。 这时候问题就暴露出来了,明明是执行了两次的++操作,但有效的却只有一次,这不科学了。。。。 这个就是线程不安全的情况啦。
jinger00 2014-07-28
  • 打赏
  • 举报
回复
引用 19 楼 jinger00 的回复:
引用 16 楼 u010793975 的回复:
没有同一个共享的资源,是线程安全的
那标题那个一个个打印字符的那个例子,也没有共享资源呀 怎么不是线程安全的呢
我这是跟着张孝祥的多线程视频敲得,请赐教哪里有问题呢
七脉 2014-07-28
  • 打赏
  • 举报
回复
再去重新学一遍去吧!!!!!!很明显你这代码敲的没话说!
jinger00 2014-07-28
  • 打赏
  • 举报
回复
引用 16 楼 u010793975 的回复:
没有同一个共享的资源,是线程安全的
那标题那个一个个打印字符的那个例子,也没有共享资源呀 怎么不是线程安全的呢
jinger00 2014-07-28
  • 打赏
  • 举报
回复
引用 15 楼 jinger00 的回复:
[quote=引用 8 楼 wu244534279 的回复:] 你最上面一段程序中,线程1和线程2之间都没有任何的数据共享,不会同时去改变某一个变量、状态,所以也就不存在线程不安全的说法了。
那我们平时用的工具类,也不是线程安全的吗?
 public static boolean isNumber(String str){
        Pattern pattern = Pattern.compile("^[0-9]+$");
        return  pattern.matcher(str).find();
    }
[/quote]但是我标题的那个例子也没有共享资源呀 怎么不是线程安全的呢
lwtbn1 2014-07-28
  • 打赏
  • 举报
回复
你把两个线程打印的东西输出到两个不同的文件,你再看看有没有混乱
lwtbn1 2014-07-28
  • 打赏
  • 举报
回复
哪里线程不安全了???仅仅是两个线程打印的东西重叠了而已嘛!
wu244534279 2014-07-28
  • 打赏
  • 举报
回复
不好意思,我上面的例子有点问题,重新整理了下,希望对楼主有些帮助。
public class ThreadTest {
	private int i = 0;

	public static void main(String[] args) {
		ThreadTest threadTest = new ThreadTest();
		new Thread(threadTest.new MyThread(), "a").start();
		new Thread(threadTest.new MyThread(), "b").start();
	}

	class MyThread implements Runnable {

		@Override
		public void run() {
			while (true) {
				System.out.println("线程" + Thread.currentThread().getName()
						+ "运行中,经过++i后,现在的i值为:" + ++i);
				
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

	}
}
注:一个线程操作共享变量时,会先到主内存空间获取这个变量副本到线程空间中,然后在线程空间对副本进行操作,最后再把操作结果写回到主内存中去。 这个例子中,a、b两条线程都会去读写共享变量i值,现在会可能出现某个时候这样的情况: 线程a把i值读进来了值是0,相当于a.i==0; 这时候到b线程开始读,这时候i值还是0,相当于b.i==0; 然后是轮到a线程它又开始执行了,这回是++a.i,然后线程a会将a.i的值也就是1传回到类变量i中,这时候类变量i的值为1; 接下来b线程继续执行,这次是++b.i,结果b.i的值是1,然后b线程也将b.i的值传回到类变量i中,这个时候类变量i的值还是1。 这时候问题就暴露出来了,明明是执行了两次的++操作,但有效的却只有一次,这不科学了。。。。 这个就是线程不安全的情况啦。
Nirvana被注册 2014-07-24
  • 打赏
  • 举报
回复
没有同一个共享的资源,是线程安全的
jinger00 2014-07-24
  • 打赏
  • 举报
回复
引用 8 楼 wu244534279 的回复:
你最上面一段程序中,线程1和线程2之间都没有任何的数据共享,不会同时去改变某一个变量、状态,所以也就不存在线程不安全的说法了。
那我们平时用的工具类,也不是线程安全的吗?
 public static boolean isNumber(String str){
        Pattern pattern = Pattern.compile("^[0-9]+$");
        return  pattern.matcher(str).find();
    }
jinger00 2014-07-24
  • 打赏
  • 举报
回复
我上面给的两个例子也没有共享资源,但并不是线程安全的,这个如何解释呢?
引用 4 楼 jinger00 的回复:
[quote=引用 1 楼 is_zhoufeng 的回复:] 第一个例子就是线程安全的,没必要弄成第二那样。 虽然你的两个线程使用的是同一个OutPut对象,但是你的output方法内并没有使用到多条线程共享的内容。
的确不是线程安全的,但是我们普通用的工具类,

    public static boolean isNumber(String str){
        Pattern pattern = Pattern.compile("^[0-9]+$");
        return  pattern.matcher(str).find();
    }
这个呢 是线程安全的吗?[/quote]
引用 4 楼 jinger00 的回复:
[quote=引用 1 楼 is_zhoufeng 的回复:] 第一个例子就是线程安全的,没必要弄成第二那样。 虽然你的两个线程使用的是同一个OutPut对象,但是你的output方法内并没有使用到多条线程共享的内容。
的确不是线程安全的,但是我们普通用的工具类,

    public static boolean isNumber(String str){
        Pattern pattern = Pattern.compile("^[0-9]+$");
        return  pattern.matcher(str).find();
    }
这个呢 是线程安全的吗?[/quote]
linfengyiye 2014-07-24
  • 打赏
  • 举报
回复
synchronized 加锁能很好的避免多线程冲突问题
linfengyiye 2014-07-24
  • 打赏
  • 举报
回复
引用 9 楼 sca4441479 的回复:
楼上的一些,我不得不说在误人子弟,现在楼主是模拟的举的线程安全的例子,你们非要紧扣线程安全是共享变量的访问,这样来回答问题,明显就是敷衍。从模拟的效果看,如果一个方法的一个字符串没在一行打印那就认为线程不安全(因为实际结果不是预想)。 好了,回答楼主问题,第一个不是线程安全,因为两个线程同时操作没有加锁的打印方法,第一个线程打印几个字符后,CPU时间片可能会切到第二个线程打印字符,这样就混乱。第二个类的方法的打印加了同步锁,很明显哪个线程先进来就保证把传进的字符串打印完才允许第二个线程进来打印。
这个说法正解
  • 打赏
  • 举报
回复
sca4441479 2014-07-24
  • 打赏
  • 举报
回复
楼上的一些,我不得不说在误人子弟,现在楼主是模拟的举的线程安全的例子,你们非要紧扣线程安全是共享变量的访问,这样来回答问题,明显就是敷衍。从模拟的效果看,如果一个方法的一个字符串没在一行打印那就认为线程不安全(因为实际结果不是预想)。 好了,回答楼主问题,第一个不是线程安全,因为两个线程同时操作没有加锁的打印方法,第一个线程打印几个字符后,CPU时间片可能会切到第二个线程打印字符,这样就混乱。第二个类的方法的打印加了同步锁,很明显哪个线程先进来就保证把传进的字符串打印完才允许第二个线程进来打印。
wu244534279 2014-07-24
  • 打赏
  • 举报
回复
你最上面一段程序中,线程1和线程2之间都没有任何的数据共享,不会同时去改变某一个变量、状态,所以也就不存在线程不安全的说法了。
wu244534279 2014-07-24
  • 打赏
  • 举报
回复
如上面两位回答所说,都是线程安全的。建议撸主百度一下,先把线程安全的概念理解清楚,这个在这里几句话也说不清。
lliiqiang 2014-07-24
  • 打赏
  • 举报
回复
上面的没有加锁,而且就算加锁,用的也不是一个字符串对象.
加载更多回复(6)

62,621

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧