java 线程 同步
publicclassTesterextendsThread{protectedstaticIntegercount=0;publicstaticvoidmain(Str...
public class Tester extends Thread{
protected static Integer count = 0;
public static void main(String[] args) {
Tester t1 = new Tester();
Tester t2 = new Tester();
t1.start();
t2.start();
}
@Override
public void run() {
methodB();
//methodA();
}
synchronized void methodA(){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
void methodB(){
synchronized(count){
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
}
程序如上,我在A,B两个方法中都加了锁,但为啥俺无论调用哪个方法,都会被另一个线程打断乜? 请高手指点..
运行结果:Thread-0 0
Thread-1 1
Thread-1 3
Thread-1 4
Thread-1 5
Thread-0 2
Thread-0 6
Thread-0 7
我是先把其中一个方法注掉,然后测试另一个....
另外,为什么上面程序在实现Runnable接口的情况下可以跑出我预想的结果,扩展Thread类却不行乜
另外的另外,为什么我将这两个方法改成static就可以实现乜?我并不是想要这个程序同步的结果,而是想清楚它的根本原因;最好能帮俺简单讲解一下和这条程序相关的java底层运行机制,按我个人的理解synchronized无非就是将加锁的代码块变为原子操作,独享CPU的时间片,不会被其他线程干扰,但实际运行情况好像和本人的理解有相当大的出入,很郁闷.... 展开
protected static Integer count = 0;
public static void main(String[] args) {
Tester t1 = new Tester();
Tester t2 = new Tester();
t1.start();
t2.start();
}
@Override
public void run() {
methodB();
//methodA();
}
synchronized void methodA(){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
void methodB(){
synchronized(count){
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
}
程序如上,我在A,B两个方法中都加了锁,但为啥俺无论调用哪个方法,都会被另一个线程打断乜? 请高手指点..
运行结果:Thread-0 0
Thread-1 1
Thread-1 3
Thread-1 4
Thread-1 5
Thread-0 2
Thread-0 6
Thread-0 7
我是先把其中一个方法注掉,然后测试另一个....
另外,为什么上面程序在实现Runnable接口的情况下可以跑出我预想的结果,扩展Thread类却不行乜
另外的另外,为什么我将这两个方法改成static就可以实现乜?我并不是想要这个程序同步的结果,而是想清楚它的根本原因;最好能帮俺简单讲解一下和这条程序相关的java底层运行机制,按我个人的理解synchronized无非就是将加锁的代码块变为原子操作,独享CPU的时间片,不会被其他线程干扰,但实际运行情况好像和本人的理解有相当大的出入,很郁闷.... 展开
6个回答
展开全部
哦,你的问题是这样的:
在某个对象实例内,synchronized Method(){}或者synchronized obj可以防止多个线程访问该对象的方法或者属性,注意这是建立在这一个对象实例的基础上。参考程序中t.methodA();场景
不同对象实例的synchronized方法是不相干扰的,你示例程序中t1和t2是两个对象,也就是两个不同的空间,两个对象实例各有一个methodA方法,所以根本两个线程可以同时访问这两个methodA方法,根本没有起到加锁的作用。如果想解决这个问题,需要在methodA方法前面加上static,这样不管有多少个Tester实例,只有并且共享这一个methodA方法,这样多线程访问这一个sychronize方法就会起到加锁的作用了。
至于methodB,这是因为count是个变量的结果,假设这样一个场景,现在count是10,线程t1独享用synchronize(10)这个methodB,而此刻线程t2想要进入methodB方法,但是碰到synchronize(10)这个锁,这样执行权又给了t1,好,t1执行第一条打印语句,System.out.println(Thread.currentThread().getName()+" "+(count++));,这时候count变成了11,这是刚要执行第二条打印语句,CPU又分配时间给t2,t2当时是因为synchronize(10)锁住的,这时候synchronize里面变量是11了,所以t2可以执行打印语句。 所以用一个变量来加锁就会导致这样的问题,根本起不到加锁的作用。 想要methodB线程同步有两种方法:
1、methodA一样前面加static
2、在Tester中添加一个静态的Object对象,用此对象加锁
修改详见下面程序:
public class Test extends Thread {
protected static Integer count = 0;
private static Object obj = new Object();
public TestSynchronize t;
public static void main(String[] args) {
TestSynchronize tt = new TestSynchronize();
Test t1 = new Test(tt);
Test t2 = new Test(tt);
t1.start();
t2.start();
}
public Test(TestSynchronize tt) {
this.t = tt;
}
@Override
public void run() {
// methodA();
// methodB();
t.methodA();
}
synchronized void methodA() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " "+ (count++));
}
}
void methodB() {
synchronized (obj) {
System.out.println(Thread.currentThread().getName() + " "+ (count++));
System.out.println(Thread.currentThread().getName() + " "+ (count++));
System.out.println(Thread.currentThread().getName() + " "+ (count++));
System.out.println(Thread.currentThread().getName() + " "+ (count++));
}
}
}
class TestSynchronize {
synchronized void methodA() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " "+ (Test.count++));
}
}
}
在某个对象实例内,synchronized Method(){}或者synchronized obj可以防止多个线程访问该对象的方法或者属性,注意这是建立在这一个对象实例的基础上。参考程序中t.methodA();场景
不同对象实例的synchronized方法是不相干扰的,你示例程序中t1和t2是两个对象,也就是两个不同的空间,两个对象实例各有一个methodA方法,所以根本两个线程可以同时访问这两个methodA方法,根本没有起到加锁的作用。如果想解决这个问题,需要在methodA方法前面加上static,这样不管有多少个Tester实例,只有并且共享这一个methodA方法,这样多线程访问这一个sychronize方法就会起到加锁的作用了。
至于methodB,这是因为count是个变量的结果,假设这样一个场景,现在count是10,线程t1独享用synchronize(10)这个methodB,而此刻线程t2想要进入methodB方法,但是碰到synchronize(10)这个锁,这样执行权又给了t1,好,t1执行第一条打印语句,System.out.println(Thread.currentThread().getName()+" "+(count++));,这时候count变成了11,这是刚要执行第二条打印语句,CPU又分配时间给t2,t2当时是因为synchronize(10)锁住的,这时候synchronize里面变量是11了,所以t2可以执行打印语句。 所以用一个变量来加锁就会导致这样的问题,根本起不到加锁的作用。 想要methodB线程同步有两种方法:
1、methodA一样前面加static
2、在Tester中添加一个静态的Object对象,用此对象加锁
修改详见下面程序:
public class Test extends Thread {
protected static Integer count = 0;
private static Object obj = new Object();
public TestSynchronize t;
public static void main(String[] args) {
TestSynchronize tt = new TestSynchronize();
Test t1 = new Test(tt);
Test t2 = new Test(tt);
t1.start();
t2.start();
}
public Test(TestSynchronize tt) {
this.t = tt;
}
@Override
public void run() {
// methodA();
// methodB();
t.methodA();
}
synchronized void methodA() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " "+ (count++));
}
}
void methodB() {
synchronized (obj) {
System.out.println(Thread.currentThread().getName() + " "+ (count++));
System.out.println(Thread.currentThread().getName() + " "+ (count++));
System.out.println(Thread.currentThread().getName() + " "+ (count++));
System.out.println(Thread.currentThread().getName() + " "+ (count++));
}
}
}
class TestSynchronize {
synchronized void methodA() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " "+ (Test.count++));
}
}
}
展开全部
上面的朋友说的都挺好,其实你需要有几点需要注意的:
1)synchronized的用法,synchronized的语法如下
synchronized(obj){
语句块
}
而其它的用法都是这个语法的变形,在Java中存在的都是对象,而每个对象都有一个和它相联系的锁。只有当线程获取了对象obj的锁,才能执行语句块;而如果obj的锁已经被别的线程获取了,那么这个线程只能等待。
2)注意线程之间要达到互斥效果,必须对同一个对象请求锁。同一个对象,这是很重要的,因为你现在出现的问题,都是因为不是同一个对象。
3)当synchronized用在方法前面时,表示synchronized(当前对象实例),也就是说需要获取当前对象实例的锁,首先t1要执行methodA方法内语句块时,获取了t1的锁;然后t2要执行methodA方法内语句块,而t2需要获取对象t2上的锁,这时t1对象处理锁定状态,但是t2并没有加锁,因此t2仍然可以获取对象t2上的锁,进而也执行methodA方法内语句块。
4)当synchronized用在静态方法前时,表示synchronized(当前类对象),对于t1和t2来说它们都属于同一个类Tester,因此它们拥有同一个类对象,所以静态方法时,它们之间可以达到互斥,因为是对同一个对象加锁。
5)针对methodB时,count是一个Integer对象,你可能认为这是一个对象,count++是修改对象的值。其实,是不正确的。这种用法从jdk1.5后,java实现了自动装箱,对于-128到127之间的整数,每一个整数都有一个对应的Integer对象,也就是当count=0是有一个Integer对象,当count++,count就变成了一个新的Integer对象。因此,当t1获取0对象的锁,执行语句;此时t2想要执行语句,发现对象0上的锁已经被其它线程获取了,这时t2等待;然后,t1执行语句,把count修改为一个新的对象1;此时t2发现对象1上的锁没有线程获取(t1获取的是0上的锁,虽然变量名都是count,但是表示不同的对象),所以t2也能进行语句块执行。
6)注意用于互次的对象不能用可变对象,所以建议这种对象前加上final关键字。
1)synchronized的用法,synchronized的语法如下
synchronized(obj){
语句块
}
而其它的用法都是这个语法的变形,在Java中存在的都是对象,而每个对象都有一个和它相联系的锁。只有当线程获取了对象obj的锁,才能执行语句块;而如果obj的锁已经被别的线程获取了,那么这个线程只能等待。
2)注意线程之间要达到互斥效果,必须对同一个对象请求锁。同一个对象,这是很重要的,因为你现在出现的问题,都是因为不是同一个对象。
3)当synchronized用在方法前面时,表示synchronized(当前对象实例),也就是说需要获取当前对象实例的锁,首先t1要执行methodA方法内语句块时,获取了t1的锁;然后t2要执行methodA方法内语句块,而t2需要获取对象t2上的锁,这时t1对象处理锁定状态,但是t2并没有加锁,因此t2仍然可以获取对象t2上的锁,进而也执行methodA方法内语句块。
4)当synchronized用在静态方法前时,表示synchronized(当前类对象),对于t1和t2来说它们都属于同一个类Tester,因此它们拥有同一个类对象,所以静态方法时,它们之间可以达到互斥,因为是对同一个对象加锁。
5)针对methodB时,count是一个Integer对象,你可能认为这是一个对象,count++是修改对象的值。其实,是不正确的。这种用法从jdk1.5后,java实现了自动装箱,对于-128到127之间的整数,每一个整数都有一个对应的Integer对象,也就是当count=0是有一个Integer对象,当count++,count就变成了一个新的Integer对象。因此,当t1获取0对象的锁,执行语句;此时t2想要执行语句,发现对象0上的锁已经被其它线程获取了,这时t2等待;然后,t1执行语句,把count修改为一个新的对象1;此时t2发现对象1上的锁没有线程获取(t1获取的是0上的锁,虽然变量名都是count,但是表示不同的对象),所以t2也能进行语句块执行。
6)注意用于互次的对象不能用可变对象,所以建议这种对象前加上final关键字。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
修改代码如下,
-------------------------1.实现Synchronized:-------------------------
public class Tester implements Runnable{
protected static Integer count = 0;
Thread th;
public Tester(String name){
th = new Thread(this);
th.setName(name);
th.start();
}
public static void main(String[] args) {
Tester t1 = new Tester("线程一");
Tester t2 = new Tester("线程二");
}
public void run() {
//methodB();
methodA();
}
synchronized void methodA(){
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" "+(i));
}
}
void methodB(){
synchronized(this){
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
}
-2.------------继承thread也可以,代码如下:------------------------
public class Tester extends Thread{
Resource re;
public Tester(String name,Resource re){
this.re = re;
this.setName(name);
this.start();
}
public static void main(String[] args) {
Resource re = new Resource();
Tester t1 = new Tester("线程一",re);
Tester t2 = new Tester("线程二",re);
}
public void run() {
//methodB();
re.methodA();
}
}
class Resource{
protected static Integer count = 0;
synchronized void methodA(){
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" "+(i));
}
}
void methodB(){
synchronized(this){
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
}
继承Thread的时候只需要加上个内部类,保证只产生一个对象就行了
-------------------------1.实现Synchronized:-------------------------
public class Tester implements Runnable{
protected static Integer count = 0;
Thread th;
public Tester(String name){
th = new Thread(this);
th.setName(name);
th.start();
}
public static void main(String[] args) {
Tester t1 = new Tester("线程一");
Tester t2 = new Tester("线程二");
}
public void run() {
//methodB();
methodA();
}
synchronized void methodA(){
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" "+(i));
}
}
void methodB(){
synchronized(this){
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
}
-2.------------继承thread也可以,代码如下:------------------------
public class Tester extends Thread{
Resource re;
public Tester(String name,Resource re){
this.re = re;
this.setName(name);
this.start();
}
public static void main(String[] args) {
Resource re = new Resource();
Tester t1 = new Tester("线程一",re);
Tester t2 = new Tester("线程二",re);
}
public void run() {
//methodB();
re.methodA();
}
}
class Resource{
protected static Integer count = 0;
synchronized void methodA(){
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" "+(i));
}
}
void methodB(){
synchronized(this){
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
}
继承Thread的时候只需要加上个内部类,保证只产生一个对象就行了
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
public class Tester extends Thread {
protected static int count = 0;
public static void main(String[] args) {
Tester t1 = new Tester();
Tester t2 = new Tester();
t1.start();
t2.start();
}
public void run() {
methodA();
}
synchronized static void methodA() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " " + (count++));
}
}
}
只需将methodA()方法设为静态即可达到你想要的效果!
对于你的代码未达到同步的原因,是因为methodA()方法是Tester类的两个实例上的,所以即使有了synchronized关键字,仍然锁不住!
synchronized关键字只能锁住一个对象,而你的是两个实例,即两个对象,所以懂了吗?
补充一点:这些楼上已经说了,百度更新也太慢了!害得我白说!
protected static int count = 0;
public static void main(String[] args) {
Tester t1 = new Tester();
Tester t2 = new Tester();
t1.start();
t2.start();
}
public void run() {
methodA();
}
synchronized static void methodA() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " " + (count++));
}
}
}
只需将methodA()方法设为静态即可达到你想要的效果!
对于你的代码未达到同步的原因,是因为methodA()方法是Tester类的两个实例上的,所以即使有了synchronized关键字,仍然锁不住!
synchronized关键字只能锁住一个对象,而你的是两个实例,即两个对象,所以懂了吗?
补充一点:这些楼上已经说了,百度更新也太慢了!害得我白说!
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
使用同步方法时别忘了Sleep方法
public class Tester extends Thread{
protected static Integer count = 0;
public static void main(String[] args) {
Tester t1 = new Tester();
Tester t2 = new Tester();
t1.start();
t2.start();
}
public void run() {
methodB();
//methodA();
try{
sleep(0);
}
catch(Exception e){
}
}
synchronized void methodA(){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
synchronized void methodB(){
synchronized(count){
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
}
public class Tester extends Thread{
protected static Integer count = 0;
public static void main(String[] args) {
Tester t1 = new Tester();
Tester t2 = new Tester();
t1.start();
t2.start();
}
public void run() {
methodB();
//methodA();
try{
sleep(0);
}
catch(Exception e){
}
}
synchronized void methodA(){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
synchronized void methodB(){
synchronized(count){
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
System.out.println(Thread.currentThread().getName()+" "+(count++));
}
}
}
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询