public class TT implements Runnable {
int b = 100;
public synchronized void m1() throws Exception{
b = 1000;
Thread.sleep(5000);
System.out.println("b = " + b);
}
public synchronized void m2() throws Exception {
Thread.sleep(2500);
b = 2000;
}
public void run() {
try {
m1();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
TT tt = new TT();
Thread t = new Thread(tt);
t.start();
tt.m2();
System.out.println(tt.b);
}
}
为什么输出的结果是: 1000
b = 1000希望大家能详细解释下锁机制!
int b = 100;
public synchronized void m1() throws Exception{
b = 1000;
Thread.sleep(5000);
System.out.println("b = " + b);
}
public synchronized void m2() throws Exception {
Thread.sleep(2500);
b = 2000;
}
public void run() {
try {
m1();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
TT tt = new TT();
Thread t = new Thread(tt);
t.start();
tt.m2();
System.out.println(tt.b);
}
}
为什么输出的结果是: 1000
b = 1000希望大家能详细解释下锁机制!
启动线程 调用线程的 public void run() {
try {
m1();
} catch(Exception e) {
e.printStackTrace();
}
}
函数的时候时间片被主线程抢走了
主线程打印完后再等里边的线程执行完后结束
A:
tt.m2()
B:
打印b
C:
看起来tt.m1()在ABC三个地方都有可能啊
是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。再结合这个程序,思考一下
tt.m2();这两句谁先谁后执行真不好说的,但是可以肯定的是你一旦把tt.m2放到t.start()前面
必然结果是2000 b=2000
因为tt.m2并不是启动了新线程,所以一定是等到m2方法执行完之后才去执行t.start()
至于你原来的写法我也说的很清楚了t.start();
tt.m2();
//一直到t.start();这句代码之前你的活动线程只有一条,但是执行到这里的时候主线程只负责调用start方法启动线程,但是线程的run代码块里面的代码的执行主线程不管,由新线程自己去控制,所以主线程会直接执行tt.m2,问题就回到我刚才说的话题上了,t.start()在代码直观的看好像在tt.m2前面,但是实际上却不一定,从计算机的工作原理来分析的话,如果是单核心的CPU同一时间只能运行一个线程,双核的CPU物理逻辑上只能同时运行两条线程,我们看到计算机同时运行个几十上百条线程的壮观只不过计算机的处理速度非常快,产生的错觉是同时进行的罢了我给你个比你这个例子更容易理解的例子吧
public class ThreadTest extends Thread{
public void run(){
for(int i=0;i<500;i++)
go();
}
synchronized void go(){
System.out.println(getName());
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().run();
}
}
线程的输出顺序并不是很整齐的吧?比如线程1进入go方法,确实其他线程都无法进入方法体,都被阻塞在外面等候,但是结果并不是
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-7
Thread-8
Thread-9
Thread-0
然后重复循环的吧,这就是线程优先级的问题,同样的优先级谁先谁后虚拟机是自动分配的,而且获得执行权限的线程也不同,每个线程能持有的CPU的占用周期每次还都不一样,就记住优先级相同虚拟机随即分配先后除非你在程序里显示的控制线程的执行,例如wait notify notifyAll等等
Thread t = new Thread(tt);
t.start(); // 1 main主线程中启动子线程,但子线程不一定立即执行tt.m2(); //2 main主线程中打印
System.out.println(tt.b);
这块代码你可以去测试,10次执行,10次都是2先执行,然后才是run中的打印。
这就是多线程:代码执行不一定就是代码的先后顺序了。因为在这里至少有2个线程在跑。如果你一定要想让1处先打印,那么你就要让main线程等到1处子线程执行完。怎么搞?
修改:
在t.start()之后添加:
t.join(); //让t这个线程执行完之后main线程才继续往下走,类似于vxWorks中的二进制信号量
tt.m2();这样,就是你想要的结果。
多谢,学习了join()方法 但是还是没有弄清 synchronized的用途!
synchronized机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态。是这样的吗?那运行 m1() 方法的时候 m2() 无法运行,在 m1() sleep的时候 ,System.out.println(tt.b)执行,故而打印出 1000 ; 之后 m1() 中的 System.out.println("b = " + b) 执行 ,打印出 b=1000我这样解释对不?我是上周开始学Java的,所以可能理解起来比较困难。所以问的比较多,比较菜,希望大家理解!
图我不画了,这里程序的入口进去之后都是只有一条活动线程,就是主线程,然后这个时候你的代码是一行一行执行的,所以你的m2方法执行的时候根本谈不上需要锁,只有一条线程,只有当你启动了线程之后才有两条线程,但是哪条跑的更快些说不定的
这里模拟下现在操作系统中有三条线程
线程1 为你的程序主线程
线程2 为你的程序主线程启动的第一条新线程
操作系统其他线程(例如IE浏览器) 1 2 3 4 5
线程1 获得执行权 启动线程2 等待执行权 获得执行权
线程2 就绪 获得执行权 IE 获得执行权
任何一个线程需要运行都要经过可运行状态 t.start(); 此时一共有两个线程,一个是主线程,一个是刚才创建的线程(暂且称为t吧) 只能说这个线程进入了可运行状态,虽然大多数时候会立即执行里面的run()方法,但是也有可能不会立即执行。至于main线程和t线程哪个先执行 完全是随机的 不能控制的 所以就可能有两个结果了 如果一定要输出第一行是b=1000的话 就需要join()语句了 可以那么改
TT tt = new TT();
Thread t = new Thread(tt);
t.start();
t.join();
tt.m2();就变成b=1000了 试一下吧 呵呵
跨度是不一样的TT tt = new TT();
Thread t = new Thread(tt); tt.m2(); //
System.out.println(tt.b); //这个时候的打印以及m2方法执行与下面的线程无关t.start(); // 这个时候虽然主线程启动了一条新线程,但是CPU的运行权限未必就给了新线程CPU的运行权还可能还在主线程这里,甚至在其他进程内的线程那里,也就是说与你的程序没关系了我们假设主线程为T1 新线程为T2 第三方的程序例如IE的某条线程我们叫IE,三线程的优先级相等T1启动一直到启动新线程,是和IE在抢CPU执行权限,但是每次拿到权限之后到底能执行多少条语句这个谁也不知道,可能T1执行一条语句后执行权交给IE,也可能是3条语句,但是执行到启动新线程T2的时候
这时候就成了三国大战了,大家一起抢CPU执行权限同样的三条线程拿到执行权的周期不定,所以每次获得执行权的时候的执行的语句数量也不定
所以可能是
T1 执行了1句----》IE执行IE的程序代码1---》T2执行3句---T1 2句而synchronized仅仅只T1和T2才有关系和IE无关,当T1进入synchronized方法后,运行了两句语句尚未将加锁的块执行完所以依然持有锁,但是这个时候计算机可能让T1把执行权限交给T2,T2执行到被synchroized修饰的块的时候就进入了阻塞,这时候可能是把CPU执行权给了T1可能是给了IE,但是肯定要等T1执行完加锁的语句块之后把锁给释放了,等到T2再次拿到CPU执行权限的时候才能进入加锁的块,当然一旦T2进入,T1就不能进入加锁的块了另外T1进入加锁的块之后,T2被阻塞,执行权继续回到T1,T1执行完加锁的块释放掉锁了,但是T2一直没有拿到CPU执行权限,而T1又拿到了并且进入了锁块又执行到一半交出权限到T2手里,T2依然还是只能等待...T2可怜了点-。-另外要学线程的话,sleep,wait,notify,notifyAll,join是必须的
int someMethod() {
....
synchronized (this) {
// some sensitive codes
}
}
26楼的 是synchronized的标准方法,楼主的是简化方式,效果一样。
同步机制中,消费者,生产者问题比较出名,建议看看。
这2个现场进入就绪队列,并让内存调入是随机的。
我也晕啦 !
一个是Thread类的方法,一个是Object的方法
sleep是休眠没错,但是执行权没有释放
wait就是完全的释放执行权了sleep(1000); 1秒钟一到立即执行下面的代码
wait(1000);要重新获得执行权才会执行下面的代码,未必立即执行