编写一个线程类,让他访问同一对象的静态资源,实现线程访问的同步
请看下面的代码:public class Test_Sync extends Thread {
Timer timer = new Timer(); //将Timer类设计成Test_Sync类的属性
//重写run()方法
public void run(){
//Thread.currentThread().getName()得到正在执行线程的名字
timer.add(Thread.currentThread().getName());//调用timer的add(String name)方法
}
public static void main(String[] args) {
Test_Sync t1 = new Test_Sync(); //得到线程Test_Sync的实例t1
Test_Sync t2 = new Test_Sync(); //得到线程Test_Sync的实例t2
t1.setName("t1"); //设置线程的名字
t2.setName("t2");
t1.start(); //启动线程
t2.start();
}
} class Timer{
private static int num = 0; //设置共享资源,请注意它的属性是static
//该方法被声明为synchronized
public synchronized void add(String name){
num ++; //每调用一次该方法num加1
try {
Thread.sleep(1); //线程休眠1ms
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+", 你是第"+num+"个访问timer的线程");
}
}这是上面代码的执行结果:
t1, 你是第2个访问timer的线程
t2, 你是第2个访问timer的线程
显然这个结果是错误的:如果将上面的代码作如下修改:public class Test_Sync implements Runnable{
public Timer t = new Timer();
public void run(){
t.add(Thread.currentThread().getName());
}
public static void main(String[] args){
Test_Sync ts1 = new Test_Sync();
Thread t1 = new Thread(ts1);
Thread t2 = new Thread(ts1);
t1.start();
t2.start();
}
}得到正确的结果应该是:
t1, 你是第1个访问timer的线程
t2, 你是第2个访问timer的线程为什么,在第一中的实现方式中add(String name)已被声明为Synchronzied,但是很明显他并没有锁住timer对象,而如果让这个线程类实现Runnable接口而不是继承Thread,则所需的功能就可以实现。所以这个问题引发了我的思考,如果要实现线程同步,对于extends Thread 和 implements Runnable,那个更好?如果两个都可以,那他们分别使用于那些情况?
请看下面的代码:public class Test_Sync extends Thread {
Timer timer = new Timer(); //将Timer类设计成Test_Sync类的属性
//重写run()方法
public void run(){
//Thread.currentThread().getName()得到正在执行线程的名字
timer.add(Thread.currentThread().getName());//调用timer的add(String name)方法
}
public static void main(String[] args) {
Test_Sync t1 = new Test_Sync(); //得到线程Test_Sync的实例t1
Test_Sync t2 = new Test_Sync(); //得到线程Test_Sync的实例t2
t1.setName("t1"); //设置线程的名字
t2.setName("t2");
t1.start(); //启动线程
t2.start();
}
} class Timer{
private static int num = 0; //设置共享资源,请注意它的属性是static
//该方法被声明为synchronized
public synchronized void add(String name){
num ++; //每调用一次该方法num加1
try {
Thread.sleep(1); //线程休眠1ms
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+", 你是第"+num+"个访问timer的线程");
}
}这是上面代码的执行结果:
t1, 你是第2个访问timer的线程
t2, 你是第2个访问timer的线程
显然这个结果是错误的:如果将上面的代码作如下修改:public class Test_Sync implements Runnable{
public Timer t = new Timer();
public void run(){
t.add(Thread.currentThread().getName());
}
public static void main(String[] args){
Test_Sync ts1 = new Test_Sync();
Thread t1 = new Thread(ts1);
Thread t2 = new Thread(ts1);
t1.start();
t2.start();
}
}得到正确的结果应该是:
t1, 你是第1个访问timer的线程
t2, 你是第2个访问timer的线程为什么,在第一中的实现方式中add(String name)已被声明为Synchronzied,但是很明显他并没有锁住timer对象,而如果让这个线程类实现Runnable接口而不是继承Thread,则所需的功能就可以实现。所以这个问题引发了我的思考,如果要实现线程同步,对于extends Thread 和 implements Runnable,那个更好?如果两个都可以,那他们分别使用于那些情况?
解决方案 »
- 启动都出错!到底什么回事啊!
- JAVA Swing 组件显示问题
- nio 的问题
- 我在命名提示符里面输入了d:\java>jar -cvf test.jar *.*
- 学习java到什么程度就可以看Jpetstore那个项目了?
- Java如何把控制台模式(就是DOS那样的)实现(模拟)在一个GUI组件中,比如JTextArea,就象Java控制台那样的效果
- 好难的问题,在线等待,问一个JAR包中包含一个XML文件,在程序中要读这个文件(只读),那么程序中的路径要怎么写
- java如何调用Lib文件
- 送分
- 如何生在ear文件?
- java 编写的爬虫 获取HTML源文件
- 高手帮解释一下添加快捷键的原理啊?
public static void main(String[] args) {
Test_Sync t1 = new Test_Sync(); //得到线程Test_Sync的实例t1
new Thread(t1,"t1").start();
new Thread(t1,"t2").start();
//得到线程Test_Sync的实例t2
// t1.setName("t1"); //设置线程的名字
// t2.setName("t2");
// t1.start(); //启动线程
// t2.start();
}
Test_Sync t1 = new Test_Sync(); //得到线程Test_Sync的实例t1
new Thread(t1,"t1").start();
new Thread(t1,"t2").start();
//得到线程Test_Sync的实例t2
// t1.setName("t1"); //设置线程的名字
// t2.setName("t2");
// t1.start(); //启动线程
// t2.start();
}
作如上修改确实实现了线程同步,但我想问您"new Thread(t1,"t2").start();"中t1实际是继承Thread,而非实现Runnable,这和API中new Thread(Runnable target, String name)不同,而编译通过,这是为什么? 谢谢!
class Timer {
private static int num = 0; //设置共享资源,请注意它的属性是static //该方法被声明为synchronized
public synchronized void add(String name) {
System.out.println("执行 add 方法"); //加上开始调用方法打印
num++; //每调用一次该方法num加1
try {
Thread.sleep(1000); //线程休眠1ms sleep改成1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ", 你是第" + num + "个访问timer的线程");
}
}在运行第一种方法,
结果:
执行 add 方法
执行 add 方法
t1, 你是第2个访问timer的线程
t2, 你是第2个访问timer的线程指所以会这样是因为你有2个Test_Sync类的对象,而每个对象里面又分别new timer()一个新的对象,而synchronized方法对于两个不同对象是不能同步的第二次你的运行结果是正确的,因为你只有一个Test_Sync对象,对于timer对象也只有一个,这样synchronized方法是可以同步的,出现的结果就是你想要的
class Thread implements Runnable
public class Thread implements Runnable {