实现的方式
实现的方式有两种,一种为继承Thread类
public
class
ThreadTestExtends
extends
Thread
{
public static void main(String[] args){
new ThreadTestExtends().start();
new ThreadTestExtends().start();
}
public void run(){
for(int i = 1; i<=10; i++){
System.out.println(i);
}
}
}
另外一种为实现Runnable接口
public
class
ThreadTestRunnable
implements
Runnable
{
public static ThreadTestRunnable a1 = new ThreadTest();
public static Thread t1 = new Thread(a1);
public static ThreadTestRunnable a2 = new ThreadTest();
public static Thread t2 = new Thread(a2);
public static void main(String[] args){
t1.start();
t2.start();
}
public void run(){
for(int i = 1; i<=10;i++){
System.out.println(i);
}
}
}
两种方式的主要区别在于:
1,Runnable接口方式给自己的类带来更大的灵活性(多继承)。
2,第一种方式由于是继承了Thread类,所以有几个线程就需要创建多少个对象。
第二种方式可以就同一对象创建多个线程。
建议使用Runnable接口方式。
synchronized关键字
synchronized用于保护共享数据。它使得多线程的运行结果得到很好的控制。
这里的共享数据指的是 同一个对象不同线程的共享数据。 它并不能控制不同对象不同线程的数据。
public
class
TestSync
implements
Runnable
{
public static void main(String[] args) {
TestSync s1 = new TestSync();
TestSync s2 = new TestSync();

Thread t1 = new Thread(s1);
// 这里数据并没有死锁,因为是两个不同对象的线程
Thread t2 = new Thread(s2);
// 这里的数据被死锁保护,因为是同一个对象的不同线程
Thread t3 = new Thread(s1);

t1.start();
t2.start();
t3.start();
}

public void run() {
synchronized (this) {
for (int i = 1; i <= 100; i++) {
System.out.println(
Thread.currentThread().getName() + " : " +
i );
}
}

}
}
再看一个例子
public
class
TestSync2
implements
Runnable
{
public static void main(String[] args){
TestSync2 sample = new TestSync2();
Thread t1 = new Thread(sample);
Thread t2 = new Thread(sample);
t1.start();
t2.start();
}
public void run(){
for(int i = 1; i<=200; i++){
System.out.println(Thread.currentThread().getName() + " no synchronised : " + i);
}
synchronized(this){
for(int i = 1; i<=200;i++){
System.out.println(Thread.currentThread().getName() + " synchronised : " + i);
}
}
}
}
这里又有一点小问题。如果你是使用继承Thread的方式,由于是创建了多个对象,所以对共享数据的控制并不理想。
public
class
TestSync3
extends
Thread
{
int i = 0;

public static void main(String[] args) {
TestSync3 t1 = new TestSync3();
TestSync3 t2 = new TestSync3();

t1.start();
t2.start();
}

public synchronized void t1() {
i = ++i;
try {
Thread.sleep(500);
} catch (Exception e) {
}
// 每个线程都进入各自的t1()方法,分别打印各自的i
System.out.println(Thread.currentThread().getName() + " " + i);
}

public void run() {
synchronized (this) {
for (int k = 1; k <= 10; k++) {
t1();
}
}

}
这里每个线程都只管自己的 i。要实现i共享的话,要将变量和方法改为static
static
int
i
=
0
;
。。。。。。。。。
public
synchronized
static
void
t1()
sleep()
sleep()会使当前线程暂停执行一段时间。
public
class
TestSleep
implements
Runnable
{

public static void main(String[] args){
TestSleep sample = new TestSleep();
new Thread(sample).start();
}
public void run(){
for(int i = 1; i<=10; i++){
if(i==5){
try{
Thread.sleep(5000);
}catch(Exception e){
e.printStackTrace();
}
}
System.out.print(" " + i);
}
}
}
再来看看下面的例子
public
class
TestSleepPriority
implements
Runnable
{
public static void main(String[] args){
TestSleepPriority sample = new TestSleepPriority();
Thread t1 = new Thread(sample);
Thread t2 = new Thread(sample);
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
public void run(){
for(int i = 1; i<=10; i++){
if(i==5){
try{
Thread.sleep(5000);
}catch(Exception e){
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " : " + i);
}
}
}
t1被设置了最高的优先级,t2为最低的优先级。如果没有sleep(5000)的话,那么t2要等到t1结束后再运行。但是由于t1暂停了5秒,所以t2有可能提前执行。如果我们设置了synchronized的话,情况又不一样。
public
class
TestSleepPrioritySync
implements
Runnable
{

public static void main(String[] args) {
TestSleepPrioritySync sample = new TestSleepPrioritySync();
Thread t1 = new Thread(sample);
Thread t2 = new Thread(sample);
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}

public void run() {
synchronized (this) {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out
.println(Thread.currentThread().getName() + " : " + i);
}
}
}
}
线程在sleep的时候是不会释放锁的。
join()
如果一个线程调用另一个线程的join(),例如t.join()。那么当线程t结束后,主线程才能继续进行。
public
class
TestJoin
implements
Runnable
{
public static int a = 0;
public static void main(String[] args){
TestJoin sample = new TestJoin();
Thread t = new Thread(sample);
t.start();
System.out.print(a);
}
public void run(){
for(int i = 0; i<100; i++){
a++;
}
}

}
上面的例子里,并不能保证每次都能让结果为100。为什么呢?当运行到t.start()的时候,线程t开始运行,但是main()方法的主线程并没有停止,它还在继续往下运行,这个时候a为什么值就打印什么值。怎么样确保得到100呢?
public
class
TestJoin
implements
Runnable
{

public static int a = 0;

public static void main(String[] args) throws InterruptedException{
TestJoin sample = new TestJoin();
Thread t = new Thread(sample);
t.start();
t.join();
System.out.print(a);
}
public void run(){
for(int i = 0; i<100; i++){
a++;
}
}

}
补充:join()方法会抛异常。
yield()
与sleep()相似,但是不能指定暂停时间。并且只能让同优先级的线程得到执行的机会。
public
class
TestYield
implements
Runnable
{

public static void main(String[] args) {
TestYield sample = new TestYield();
Thread t1 = new Thread(sample, "t1");
Thread t2 = new Thread(sample, "t2");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}

public void run() {

for (int i = 1; i <= 10; i++) {
if (i== 5 && Thread.currentThread().getName().equals("t1")) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + " : " + i);
}
}
}
wait(), notify(), notifyAll()
与sleep()不同,他们只能在synchronized方法或者是synchronized段中使用,否则运行时会抛异常。
经典的生产者消费者问题:
/**
* 生产者消费者问题
*
* @author chengyumin
*
*/
public
class
ProdecerConsumer
{
public static void main(String[] args) {
SyncStack ss = new SyncStack();
Producer p = new Producer(ss);
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(c).start();
}

}

class
WoTou
{
int id;

WoTou(int id) {
this.id = id;
}

public String toString() {
return "WoTou : " + id;
}
}

class
SyncStack
{
int index = 0;

WoTou[] arrWT = new WoTou[6];

public synchronized void push(WoTou wt) {
while (index == arrWT.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
arrWT[index] = wt;
index++;
}

public synchronized WoTou pop() {
while (index == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
index--;
return arrWT[index];
}
}

class
Producer
implements
Runnable
{
SyncStack ss = null;

Producer(SyncStack ss) {
this.ss = ss;
}

public void run() {
for (int i = 0; i < 20; i++) {
WoTou wt = new WoTou(i);
ss.push(wt);
System.out.println("生产了:" + wt);
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}

}

class
Consumer
implements
Runnable
{
SyncStack ss = null;

Consumer(SyncStack ss) {
this.ss = ss;
}

public void run() {
for (int i = 0; i < 20; i++) {
WoTou wt = ss.pop();
System.out.println("消费了:" + wt);
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}

}
死锁
/**
* 测试死锁
* @author chengyumin
*
*/
public
class
TestDeadLock
implements
Runnable
{
public int flag = 1;
static Object o1 = new Object();
static Object o2 = new Object();
public void run(){
System.out.println("flag = " + flag);
if(flag == 1){
synchronized(o1){
try{
Thread.sleep(500);
}catch(Exception e){
e.printStackTrace();
}
synchronized(o2){
System.out.println("1");
}
}
}
if(flag == 0){
synchronized(o2){
try{
Thread.sleep(500);
}catch(Exception e){
e.printStackTrace();
}
synchronized(o1){
System.out.println("0");
}
}
}
}
public static void main(String[] args){
TestDeadLock td1 = new TestDeadLock();
TestDeadLock td2 = new TestDeadLock();
td1.flag = 1;
td2.flag = 0;
Thread t1 = new Thread(td1);
Thread t2 = new Thread(td2);
t1.start();
t2.start();
}

}
===================================================================================
实现的方式有两种,一种为继承Thread类












另外一种为实现Runnable接口





















两种方式的主要区别在于:
1,Runnable接口方式给自己的类带来更大的灵活性(多继承)。
2,第一种方式由于是继承了Thread类,所以有几个线程就需要创建多少个对象。
第二种方式可以就同一对象创建多个线程。
建议使用Runnable接口方式。
synchronized关键字
synchronized用于保护共享数据。它使得多线程的运行结果得到很好的控制。
这里的共享数据指的是 同一个对象不同线程的共享数据。 它并不能控制不同对象不同线程的数据。


























再看一个例子


























这里又有一点小问题。如果你是使用继承Thread的方式,由于是创建了多个对象,所以对共享数据的控制并不理想。





























这里每个线程都只管自己的 i。要实现i共享的话,要将变量和方法改为static




sleep()
sleep()会使当前线程暂停执行一段时间。




















再来看看下面的例子




























t1被设置了最高的优先级,t2为最低的优先级。如果没有sleep(5000)的话,那么t2要等到t1结束后再运行。但是由于t1暂停了5秒,所以t2有可能提前执行。如果我们设置了synchronized的话,情况又不一样。




























线程在sleep的时候是不会释放锁的。
join()
如果一个线程调用另一个线程的join(),例如t.join()。那么当线程t结束后,主线程才能继续进行。


















上面的例子里,并不能保证每次都能让结果为100。为什么呢?当运行到t.start()的时候,线程t开始运行,但是main()方法的主线程并没有停止,它还在继续往下运行,这个时候a为什么值就打印什么值。怎么样确保得到100呢?



















补充:join()方法会抛异常。
yield()
与sleep()相似,但是不能指定暂停时间。并且只能让同优先级的线程得到执行的机会。























wait(), notify(), notifyAll()
与sleep()不同,他们只能在synchronized方法或者是synchronized段中使用,否则运行时会抛异常。
经典的生产者消费者问题:










































































































死锁
























































===================================================================================