一线程共享数据
a)继承Thread那么我们可以创建很多个这样的类但是每个这样的类都是相互不关联的也就是说我们Thread类中的内容每个创建出来的类都有一份因此它不适合作为数据共享的线程来操作同时由于Java继承的唯一性我们只能继承一个对象
b)使用runnable就可以解决唯一性和不能共享的问题(不是说使用runnable就解决了共享问题只是相对于创建Thread来说它可以算的上是共享了为了获得更精确的共享问题它必须的使用线程同步操作)实现了runnable接口的类比较适合用作共享数据
一个测试例子à证明runnable能实现数据共享thread不能
Thread_thread一个继承了Thread的线程
Thread_runnable是一个时间了runnable的接口他们在run里面有共同的方法
for(int i=;i<;i++){
if(ticket>){
Systemoutprintln(ticket);
ticket;
}
}
thread_thread th=new thread_thread();
thread_thread th=new thread_thread();
thread_thread th=new thread_thread();
thstart();
thstart();
thstart();
输入了三组
因为创建的是三个对象每一个对象都拥有自己的一个备份
将一个runnable作为参数实例化三个thread对象
thread_runnable ru=new thread_runnable();
Thread th=new Thread(ru);
Thread th=new Thread(ru);
Thread th=new Thread(ru);
thstart();
thstart();
thstart();
输入了
虽然说着不是完整意义上的数据共享但是相当于上述打印三组完整的数据来说它已经实现了数据共享我们从中也可以看到我们只创建了一个runnable对象(数据只产生了一份)它由三个Thread调用
新建三个runnable对象分别给每一个thread传递
Thread th=new Thread(new thread_runnable());
Thread th=new Thread(new thread_runnable());
Thread th=new Thread(new thread_runnable());
thstart();
thstart();
thstart();
打印结果是
我们可以看到我们产生了三个runnable对象每一个都有自己的一份使用
综上所述只有将一个runnable对象作为参数传递给thread对象才能实现数据共享
注意当我们创建一个Thread对象并多次调用start方法的时候系统是不会给你创建多个Thread线程的它只会运行那个唯一的Thread一次而已也就是说你运行了一次start方法之后再调用一个它的start方法是没有意义的(那个Thread没有结束的情况下)系统不会给你多次运行的
二线程同步
a)线程代码块(在代码中添加Synchronized(对象){})
iSynchronized(对象)每个对象都有个标志位当我们进入synchronized代码块中系统就让这个对象的标志位变为就相当于给这个对象添加上了一把锁当别的代码运行到这个代码块的时候因为加了锁所以不能进去当第一个程序它运行出去之后系统就会让标志位变为相当于解锁这样别的代码又可以访问了从而实现同步(安全)操作
ii当我们将我们的标志位对象放在run方法里面定义的时候我们是不能实现同步的因为我们每次运行一个线程都将调用它的run方法从而每次都会创建一个新的标志位对象也就是说我们所有的run方法都含有自己的一个标志位对象因此不能实现加锁的过程一般都是放在runnable接口中进行定义的
b)线程方法(在代码的方法申明中public和void之间添加synchronized)
i每次只能有一个线程调用这个同步方法而且每次这个方法都得运行完这就是同步代码方法
ii同步方法默认使用的是this来作为标志对象位的这个this就是我们的当前类
c)注意
i当一个同步代码块和一个同步代码方法使用的不是同一个对象作为标志位的时候它们就不会实现同步这也就是数当两个同步代码块不使用同一个对象作为标志位那他们就不能实现同步
ii调用线程的Start方法的时候并没有真正的运行这个代码而只是说这个代码已经准备就绪有运行的可能
三线程通信
a)当我们的代码中使用了synchronized(对象)同步代码块的时候如果我们想实现线程通信也就是如果我们想使用waitnotify或者notifyall时我们必须在静态代码块中使用对象wait()对象notify()对象notifyAll()来通信不然的话讲会报Illegal的错误
b)Notify是唤醒同一监视器下(相当于同一个标志位对象)的第一个wait线程而notifyall是唤醒所有的处于同一监视器下的(同一标志位对象)的线程