Java的面向?qū)ο缶幊?/a>">Java的面向?qū)ο缶幊?/a>
679
2025-04-02
0. 用runnable創(chuàng)建線程具有面向?qū)ο蟮乃枷搿?/p>
1. quartz ?定時(shí)器開(kāi)源庫(kù)。
3. ?多線程間的互斥:
(1)多線程間的互斥,用synchronized關(guān)鍵字,兩個(gè)線程用互斥鎖必須用同一個(gè)對(duì)象才能實(shí)現(xiàn)互斥。
(2) 兩個(gè)非靜態(tài)函數(shù)前加synchronized關(guān)鍵字,它們的公用鎖是this,就是當(dāng)前對(duì)象實(shí)例。
(3)靜態(tài)函數(shù)前加synchronized關(guān)鍵字,它用的鎖對(duì)象是.class字節(jié)碼,這個(gè)時(shí)u候與要將非靜態(tài)函數(shù)的synchronized(this)鎖改為synchronized(MyClass.class),即字節(jié)碼鎖
兩個(gè)函數(shù)這才使用了同一個(gè)鎖:類(lèi)的字節(jié)碼對(duì)象,從而才實(shí)現(xiàn)了互斥。
例如:2 個(gè)線程調(diào)用同一個(gè)Output對(duì)象的output1(“gaoxiaowei”)和output2(“l(fā)ichao”)兩個(gè)函數(shù), 會(huì)出現(xiàn)打印gaoxiaowei ?lichao ? ?gaolichao xiaowei這樣第二行錯(cuò)亂的問(wèn)題。
在這里臨界資源是輸出屏幕? 我如果讓一個(gè)線程調(diào)用ouput1對(duì)象的output,然后另一個(gè)線程調(diào)用output2對(duì)象的output,在不加鎖的情況下會(huì)錯(cuò)亂嗎?
答:
(1)如果output函數(shù)的同步鎖是object.class字節(jié)碼時(shí),就不會(huì)錯(cuò)亂,因?yàn)閮蓚€(gè)線程 的兩個(gè)output對(duì)象在執(zhí)行output1函數(shù)時(shí),用的是同一把鎖object.class;
(2)如果output的同步鎖是this,那么會(huì)錯(cuò)亂,因?yàn)閮蓚€(gè)線程分別持有2個(gè)對(duì)象output1與ouput2,是兩個(gè)this,因此output函數(shù)上的synchronized用的o是2把不同的
this鎖,各自執(zhí)行各自的,都可以在這個(gè)臨界資源——屏幕上輸出。如第一個(gè)線程正在輸出gaolichao結(jié)果第二個(gè)線程打印lichao插到了第一個(gè)線程的輸出中間。
(3)是的,這里的臨界資源就是顯示器,而不是公用的output類(lèi)對(duì)象,因?yàn)榧词?個(gè)線程分別創(chuàng)建一個(gè)output對(duì)象:output1與output2,如果鎖不是同一個(gè)的話,
也會(huì)出現(xiàn)打印錯(cuò)誤。除非有2個(gè)顯示器,一個(gè)線程往顯示器1輸出,另一個(gè)線程往顯示器2輸出,這才不沖突,因?yàn)?個(gè)已經(jīng)是1對(duì)1,不存在公用競(jìng)爭(zhēng)問(wèn)題。
4.多線程間的同步
wait 和 notify
現(xiàn)在有這么一個(gè)題目:子線程執(zhí)行10次,然后主線程再執(zhí)行100次,接著輪到子線程再執(zhí)行10次,然后主線程又執(zhí)行100次,兩個(gè)線程這樣輪流執(zhí)行,總共50回。
step1: 定義一個(gè)業(yè)務(wù)類(lèi),封裝兩個(gè)函數(shù):(1)打印10次sub ?(2)打印100次main;
step2: 定義1個(gè)子線程,外層for循環(huán)都是50次,然后每循環(huán)1次調(diào)用業(yè)務(wù)類(lèi)中的 函數(shù)(1u)打印10次sub
主線程,外層for循環(huán)都是50次,然后每循環(huán)1次調(diào)用業(yè)務(wù)類(lèi)中的 函數(shù)(2)打印50次main
step3:先解決互斥問(wèn)題:就是在打印sub的10次循環(huán)時(shí),不能穿插打印main;同理打印main的100次的時(shí)候,不能穿插子線程的sub打印。這個(gè)好辦,給業(yè)務(wù)類(lèi)的
函數(shù)1和函數(shù)2前加synchronized關(guān)鍵字,這樣就實(shí)現(xiàn)了打印sub的10次時(shí),由于正在占用同一個(gè)對(duì)象鎖this,因此它不會(huì)被函數(shù)(2)打斷。
step4:解決同步配合問(wèn)題,先子線程打印10次,子線程打印完了,然后執(zhí)行notify,喚醒主線程去打印100次(主線程剛開(kāi)始會(huì)調(diào)用waite),然后主線程打印完100次,再去喚醒子線程去打印。
注意synchronized括起來(lái)的對(duì)象要與調(diào)用wait,notify是同一個(gè)對(duì)象,并且這個(gè)object.notify,object.wait中的object要被括在synchronized里,否則會(huì)報(bào)錯(cuò):Java.lang.IllegalMonitorStateException
實(shí)例代碼如下:
import Java.util.concurrent.atomic.AtomicInteger;
public class TraditionalThreadCommunication {
/**
* @param args
*/
public static void main(String[] args) {
final Business business = new Business();
new Thread(
new Runnable() {
@Override
public void run() {
for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();
for(int i=1;i<=50;i++){
business.main(i);
}
}
}
class Business {
private boolean bShouldSub = true;
Object obj;
public Business()
{
obj = new Object();
}
public synchronized void sub(int i){
synchronized(obj)
{
while(!bShouldSub){
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
obj.notify();
}
}
public ?void main(int i){
synchronized(obj)
{
while(bShouldSub){
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
bShouldSub = true;
obj.notify();
}
}
}
或者:
public class TraditionalThreadCommunication {
public static void main(String[] args) {
final Business business = new Business();
new Thread(
new Runnable() {
@Override
public void run() {
for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();
for(int i=1;i<=50;i++){
business.main(i);
}
}
}
class Business {
private boolean bShouldSub = true;
public synchronized void sub(int i){
while(!bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
this.notify();
}
public synchronized void main(int i){
while(bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
bShouldSub = true;
this.notify();
}
}
5. 多線程間的互斥,用synchronized關(guān)鍵字包裹的函數(shù)內(nèi)部如果生成了 一個(gè)死循環(huán)線程,那么這個(gè)函數(shù)的鎖子能釋放嗎?
答:能。因?yàn)閟ynchronized是用于當(dāng)前線程同步的;還有就是生成的那個(gè)線程并不會(huì)阻塞當(dāng)前函數(shù)的執(zhí)行,函數(shù)執(zhí)行完成后自然會(huì)釋放synchronized鎖。
6.當(dāng)一個(gè)線程處于sleep時(shí),Thread.isAlive函數(shù)返回false
7.線程范圍內(nèi)的共享變量
同一個(gè)變量,在線程間共享,例如下面的變量x,線程內(nèi)獨(dú)立,表示線程內(nèi)是一份獨(dú)立的數(shù)據(jù)。
(1)可以用hashmap.put(Thread.name, data);? 來(lái)實(shí)現(xiàn)
(2)ThreadLocal來(lái)實(shí)現(xiàn)
下面的x,是演示單個(gè)共享變量
package cn.itcast.heima2;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadLocalTest {
private static ThreadLocal
private static ThreadLocal
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()
+ " has put data :" + data);
x.set(data);
/*?? ??? ??? ??? ??? ?MyThreadScopeData myData = new MyThreadScopeData();
myData.setName("name" + data);
myData.setAge(data);
myThreadScopeData.set(myData);*/
MyThreadScopeData.getThreadInstance().setName("name" + data);
MyThreadScopeData.getThreadInstance().setAge(data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
int data = x.get();
System.out.println("A from " + Thread.currentThread().getName()
+ " get data :" + data);
/*?? ??? ??? ?MyThreadScopeData myData = myThreadScopeData.get();;
System.out.println("A from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());*/
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("A from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());
}
}
static class B{
public void get(){
int data = x.get();
System.out.println("B from " + Thread.currentThread().getName()
+ " get data :" + data);
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("B from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());
}
}
}
class MyThreadScopeData{
private MyThreadScopeData(){}
public static /*synchronized*/ MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance = map.get();
if(instance == null){
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}
//private static MyThreadScopeData instance = null;//new MyThreadScopeData();
private static ThreadLocal
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
8.多個(gè)線程間共享數(shù)據(jù)的探討
方法1:new Thread(new Runnable()
{
data1.decrement();
}
)
方法2:?? ??? ?new Thread(new MyRunnable1(data2)).start();
new Thread(new MyRunnable2(data2)).start();
將數(shù)據(jù)data2作為構(gòu)造函數(shù)參數(shù)傳到Runnable里去。
方法3:
定義2個(gè)Runnable內(nèi)部類(lèi),訪問(wèn)外部類(lèi)的成員變量j
方法1和方法2的代碼:
package cn.itcast.heima2;
public class MultiThreadShareData {
private static ShareData1 data1 = new ShareData1();
public static void main(String[] args) {
ShareData1 data2 = new ShareData1();
new Thread(new MyRunnable1(data2)).start();
new Thread(new MyRunnable2(data2)).start();
final ShareData1 data1 = new ShareData1();
new Thread(new Runnable(){
@Override
public void run() {
data1.decrement();
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
data1.increment();
}
}).start();
}
}
class MyRunnable1 implements Runnable{
private ShareData1 data1;
public MyRunnable1(ShareData1 data1){
this.data1 = data1;
}
public void run() {
data1.decrement();
}
}
class MyRunnable2 implements Runnable{
private ShareData1 data1;
public MyRunnable2(ShareData1 data1){
this.data1 = data1;
}
public void run() {
data1.increment();
}
}
class ShareData1 /*implements Runnable*/{
/*?? ??? ?private int count = 100;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
count--;
}
}*/
private int j = 0;
public synchronized void increment(){
j++;
}
public synchronized void decrement(){
j--;
}
}
方法3的代碼:
外部類(lèi):
private int j = 0;
public synchronized void increment(){
j++;
}
public synchronized void decrement(){
j--;
}
內(nèi)部類(lèi):
MyIncrementRunnable()
{
increment();? //內(nèi)部類(lèi)調(diào)用外部類(lèi)成員,還是以外部類(lèi)對(duì)象為同步鎖
}
MyDecrementRunnable()
{
decrement();
}
Java 任務(wù)調(diào)度
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。