多线程课程001:线程安全的问题


package com.lee.thread;

public class TraditionalThreadSynchronized {

public static void main(String[] args) {
//静态方法中不能new内部类的实例对象
new TraditionalThreadSynchronized().init();

}

private void init(){
final Outputer outputer = new Outputer();
//线程1
new Thread(new Runnable(){

@Override
public void run() {
while(true){
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
outputer.output("zhangxiaoxiang");
}
}

}).start();

//线程2
new Thread(new Runnable(){

@Override
public void run() {
while(true){
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
outputer.output("lihuoming");
}
}

}).start();
}
class Outputer{
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();
}
}
}



线程1和线程2在外部类的init方法中,同时开启了,两个线程夺取内部类的资源,于是会出现线程1夺取一半时,线程2过来夺取。而本意是想,线程1执行一个,线程2执行一个。
输出结果如下:

zhangxiaoxlihuoming
iang
lihuozhanming
gxiaoxiang
lihuoming
zhangxiaoxiang
lihuoming
zhangxiaoxiang
lihzhangxiaoxiang
uoming
lihuozhming


因此,出现了所谓的线程安全隐患。

保证原子性,需要给并发的代码块加锁。
不过下面的方式是错误的


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

synchronized里边的是一个栓子,应该是所有线程对象都用的是同一个栓子才可以达到互斥的效果。上面的写法,每个线程都有自己的传过来的不同的name,因此,起不到互斥效果。
输出效果如下:

ang
lihuoming
zhangxiaoxiang
lihuoming
zhangxiaoxiang
lizhangxiaoxiang
huoming
lihuomzhangxiaoxiang
ing


因此,实现互斥的锁,应该是每个线程都持有的一样的一把锁(这把锁必须是同一个对象的,如果每个线程都new了一个Outputer就不能实现互斥了,因为不是同一个对象),因此,可以在类中定义一个String s,那么每个在使用这个类时,使用的锁都是s锁,可以实现互斥的效果。

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


输出结果如下:

lihuoming
lihuoming
zhangxiaoxiang
lihuoming
zhangxiaoxiang
zhangxiaoxiang
lihuoming
zhangxiaoxiang
lihuoming
lihuoming
zhangxiaoxiang
zhangxiaoxiang


可以使用当前对象this作为锁,这样也可以实现互斥,因为他们都是来自同一个唯一的new出来的对象。

class Outputer{

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


当两个线程分别调用下面两个方法的时候,也可以实现互斥的效果,因为这两个方法都是使用this作为锁。

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

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

输出结果如下:

zhangxiaoxiang
lihuoming
zhangxiaoxiang
lihuoming
zhangxiaoxiang
lihuoming


静态时,不与锁关系,但是最好还是加

static class Outputer {

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

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

public static synchronized void output3(String name) {
{
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值