第一章:Java多线程技能
Java实现多线程的方式
1 继承Thread类(不支持多继承),2 实现Runnable接口
线程调用有随机性。
package com.java.mul;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyThread mythread = new MyThread();
mythread.setName("myThread");
mythread.start();
for(int count = 0;count<10;count++) {
int time = (int) (Math.random() * 1000);
Thread.sleep(time);
System.out.println("main="+Thread.currentThread().getName());
}
System.out.println("finish");
}
}
package com.java.mul;
public class MyThread extends Thread{
@Override
public void run() {
super.run();
System.out.println("MyThread");
for(int count = 0;count<10;count++) {
try {
int time = (int) (Math.random() * 1000);
Thread.sleep(time);
System.out.println("run="+Thread.currentThread().getName());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
结果
MyThread
main=main
run=myThread
main=main
run=myThread
main=main
main=main
run=myThread
run=myThread
main=main
run=myThread
main=main
run=myThread
run=myThread
main=main
run=myThread
main=main
run=myThread
main=main
main=main
finish
run=myThread
共享与不共享
共享(产生了非线程安全问题)
package com.java.mul;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyThread mythread = new MyThread();
Thread a = new Thread(mythread,"A");
Thread b = new Thread(mythread,"B");
Thread c = new Thread(mythread,"C");
Thread d = new Thread(mythread,"D");
Thread e = new Thread(mythread,"E");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
package com.java.mul;
public class MyThread extends Thread{
private int count = 5;
@Override
public void run() {
super.run();
count--;
System.out.println("由"+Thread.currentThread().getName()+"计算,count="+count);
}
}
package com.java.mul;
public class myRunnable implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("run");
}
}
解决:synchronized
package com.java.mul;
public class MyThread extends Thread{
private int count = 5;
@Override
synchronized public void run() {
super.run();
count--;
System.out.println("由"+Thread.currentThread().getName()+"计算,count="+count);
}
}
(isAlive,在this和Thread.currentThread()之间,会有不同的调用结果,主要原因在于this和Thread.currentThread()的差异)
停止线程:
Thread.stop()(不安全)(一般不用)
大多数使用Thread.interrupt()(interrupt方法仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程)
Thread.interrupted()
Thread.currentThread().interrupt();
System.out.println("是否停止1? = " + Thread.interrupted());
System.out.println("是否停止2? =" + Thread.interrupted());
System.out.println("end!");
结果为
是否停止1? = true
是否停止2? =false
end!
这样的结果是因为,interrupted的第一次调用,会返回true并且清除当前中断当前interrupted检测到为true的状态
与interrupted共同使用的不用break,用throw,这样可以继续执行后面的代码
package com.java.mul;
public class MyThread extends Thread{
private int count = 5;
@Override
public void run() {
super.run();
for(int i = 0;i<500000;i++) {
if(this.interrupted()) {
System.out.println("已经停止");
//break;
try {
throw new InterruptedException();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("i="+i+1);
}
System.out.println("在for下面");
}
}
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyThread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
}
}
如果在sleep状态下停止线程,会进入catch语句,并且清除停止状态值,使之变成false
先停止,再sleep,也不行,会进入catch
package com.java.mul;
public class MyThread extends Thread{
private int count = 5;
@Override
public void run() {
super.run();
try {
for(int i=0;i<100000;i++) {
System.out.println("i=" +(i+1));
}
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println("sleep stop");
e.printStackTrace();
}
}
}
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyThread thread = new MyThread();
thread.start();
thread.interrupt();
System.out.println("end!");
}
}
stop方法强制停止线程(会抛出不显示捕捉的ThreadDeath异常)(stop方法已经被作废)
interrupted与return结合也能实现停止线程的效果,不过还是推荐使用throw
暂停线程
suspend()方法暂停线程(过期作废的方法)
resume()方法恢复暂停线程(过期作废的方法)
在使用这两个方法的时候,如果使用不当,极易造成公共的同步对象的独占。
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyThread thread = new MyThread();
thread.start();
Thread.sleep(5000);
thread.suspend();
System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
Thread.sleep(5000);
System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
thread.resume();
Thread.sleep(5000);
thread.suspend();
System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
Thread.sleep(5000);
System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
}
}
package com.java.mul;
public class MyThread extends Thread{
private int count = 5;
private long i = 0;
public long getI() {
return i;
}
public void setI(long i) {
this.i = i;
}
@Override
public void run() {
while(true) {
i++;
}
}
}
yield
(作用是放弃当前CPU资源,将它让给其他任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片)
package com.java.mul;
public class MyThread extends Thread{
@Override
public void run() {
long beginTime = System.currentTimeMillis();
int count=0;
for(int i=0;i<50000000;i++) {
Thread.yield();
count = count + (i + 1);
}
long endTime = System.currentTimeMillis();
System.out.println("用时:"+(endTime - beginTime)+"毫秒! ");
}
}
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyThread thread = new MyThread();
thread.start();
}
}
setPriority设置线程优先级(1-10),优先级具有继承性,比如A线程启动B线程,那么他们的优先级一致。
优先级具有规则性,高优先级的线程总是大部分先执行完,但是高优先级的并不是每次都是先执行完。
守护线程
当进程中不存在非守护线程了,守护线程自动销毁,典型的守护线程(垃圾回收线程(GC))
package com.java.mul;
public class MyThread extends Thread{
private int i= 0;
@Override
public void run() {
long beginTime = System.currentTimeMillis();
try {
while(true) {
i++;
System.out.println("i=" + (i));
Thread.sleep(1000);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyThread thread = new MyThread();
thread.setDaemon(true);
thread.start();
Thread.sleep(5000);
System.out.println("stop");
}
}
第二章:对象及变量的并发访问
线程安全
1 private修饰的变量
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
HasSelfPrivateNum numRef = new HasSelfPrivateNum();
MyThread thread = new MyThread(numRef);
thread.start();
ThreadA threada = new ThreadA(numRef);
threada.start();
}
}
package com.java.mul;
public class HasSelfPrivateNum {
public void addI(String username) {
try {
int num = 0;
if(username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000);
}else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package com.java.mul;
public class MyThread extends Thread{
private HasSelfPrivateNum numRef;
public MyThread(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
}
@Override
public void run() {
super.run();
numRef.addI("a");
}
}
package com.java.mul;
public class ThreadA extends Thread{
private HasSelfPrivateNum numRef;
public ThreadA(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
}
@Override
public void run() {
super.run();
numRef.addI("b");
}
}
synchronized锁重入
在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的,如果不可锁重入的话,就会造成死锁。
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyThread thread = new MyThread();
thread.start();
}
}
package com.java.mul;
public class MyThread extends Thread{
@Override
public void run() {
Service service = new Service();
service.service1();
}
}
package com.java.mul;
public class Service {
synchronized public void service1() {
System.out.println("service1");
service2();
}
synchronized public void service2() {
System.out.println("service2");
service3();
}
synchronized public void service3() {
System.out.println("service3");
}
}
可重入锁也支持在父子类继承的环境中
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyThread thread = new MyThread();
thread.start();
}
}
package com.java.mul;
public class MyThread extends Thread{
@Override
public void run() {
Sub sub = new Sub();
sub.operateISubMethod();
}
}
package com.java.mul;
public class Main {
public int i = 10;
synchronized public void operateIMainMethod() {
try {
i--;
System.out.println("main print i=" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package com.java.mul;
public class Sub extends Main{
synchronized public void operateISubMethod() {
try {
while(i>0) {
i--;
System.out.println("sub print i=" + i);
Thread.sleep(100);
this.operateIMainMethod();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
出现异常,锁自动释放
同步不可以被继承
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Sub subRef = new Sub();
MyThreadA a = new MyThreadA(subRef);
a.setName("A");
a.start();
MyThreadB b = new MyThreadB(subRef);
b.setName("B");
b.start();
}
}
package com.java.mul;
public class Main {
synchronized public void serviceMethod() {
try {
System.out.println("int main" + Thread.currentThread().getName() + "time="+ System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("int main" + Thread.currentThread().getName() + "time="+ System.currentTimeMillis());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package com.java.mul;
public class Sub extends Main{
public void serviceMethod() {
try {
System.out.println("int main" + Thread.currentThread().getName() + "time="+ System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("int main" + Thread.currentThread().getName() + "time="+ System.currentTimeMillis());
super.serviceMethod();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package com.java.mul;
public class MyThreadA extends Thread{
private Sub sub;
public MyThreadA(Sub sub) {
super();
this.sub = sub;
}
@Override
public void run() {
sub.serviceMethod();
}
}
package com.java.mul;
public class MyThreadB extends Thread{
private Sub sub;
public MyThreadB(Sub sub) {
super();
this.sub = sub;
}
@Override
public void run() {
sub.serviceMethod();
}
}
synchronized(this)同步语句块,是对某一个对象进行加锁
当线程访问同一个object的一个synchronized(this)代码块时,其他线程对同一个object中的所有其他synchronized(this)同步代码块的访问将被阻塞
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ObjectService service = new ObjectService();
MyThreadA a = new MyThreadA(service);
a.setName("A");
a.start();
MyThreadB b = new MyThreadB(service);
b.setName("B");
b.start();
}
}
package com.java.mul;
public class MyThreadA extends Thread{
private ObjectService service;
public MyThreadA(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethodA();
}
}
package com.java.mul;
public class MyThreadB extends Thread{
private ObjectService service;
public MyThreadB(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
service.serviceMethodB();
}
}
package com.java.mul;
public class ObjectService {
public void serviceMethodA() {
try {
synchronized(this) {
System.out.println("A begin time="+ System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("A end time="+ System.currentTimeMillis());
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void serviceMethodB() {
synchronized(this) {
System.out.println("B begin time="+ System.currentTimeMillis());
System.out.println("B end time="+ System.currentTimeMillis());
}
}
}
synchronized(其他对象)(与this是异步的)(因为this与其他对象,不是一个对象,不是一个对象监视器,异步)
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ObjectService service = new ObjectService();
MyThreadA a = new MyThreadA(service);
a.setName("A");
a.start();
MyThreadB b = new MyThreadB(service);
b.setName("B");
b.start();
}
}
package com.java.mul;
public class MyThreadA extends Thread{
private ObjectService service;
public MyThreadA(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.setUsernamePassword("b", "aa");
}
}
package com.java.mul;
public class MyThreadB extends Thread{
private ObjectService service;
public MyThreadB(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
service.setUsernamePassword("b", "bb");
}
}
package com.java.mul;
public class ObjectService {
private String usernameParam;
private String passwordParam;
private String anyString = new String();
public void setUsernamePassword(String username,String password) {
try {
synchronized(anyString) {
System.out.println("name:"+Thread.currentThread().getName()+"zzai"+System.currentTimeMillis()+"enter");
usernameParam = username;
Thread.sleep(3000);
passwordParam = password;
System.out.println("name:"+Thread.currentThread().getName()+"zzai"+System.currentTimeMillis()+"leave");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void serviceMethodA() {
try {
synchronized(this) {
System.out.println("A begin time="+ System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("A end time="+ System.currentTimeMillis());
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void serviceMethodB() {
synchronized(this) {
System.out.println("B begin time="+ System.currentTimeMillis());
System.out.println("B end time="+ System.currentTimeMillis());
}
}
}
synchronized关键字可以应用在static静态方法上,如果这样写,是对当前java文件对应的Class类进行持锁。class锁可以对类的所有对象示例起作用。效果与synchronized(class)代码块的作用一致。(synchronized(Service.class))
JVM中具有String常量池缓存的功能,当synchronized(string)同步块与String联合使用时,要注意常量池带来的一些例外。
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Service service = new Service();
MyThreadA a = new MyThreadA(service);
a.setName("A");
a.start();
MyThreadB b = new MyThreadB(service);
b.setName("B");
b.start();
}
}
package com.java.mul;
public class MyThreadA extends Thread{
private Service service;
public MyThreadA(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.print("AA");
}
}
package com.java.mul;
public class MyThreadB extends Thread{
private Service service;
public MyThreadB(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.print("AA");;
}
}
package com.java.mul;
public class Service {
public static void print(String stringParam) {
try {
synchronized (stringParam) {
while(true) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
B线程会被阻塞,因为String的两个值都为AA,两个线程持有相同的锁。这就是String常量池带来的问题,因此大多数情况下,同步synchronized代码块都不使用String作为锁对象。而改用new Object()实例化一个Object对象,但它并不放入缓存中。
package com.java.mul;
import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;
public class multest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Service service = new Service();
MyThreadA a = new MyThreadA(service);
a.setName("A");
a.start();
MyThreadB b = new MyThreadB(service);
b.setName("B");
b.start();
}
}
package com.java.mul;
public class MyThreadA extends Thread{
private Service service;
public MyThreadA(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.print(new Object());
}
}
package com.java.mul;
public class MyThreadB extends Thread{
private Service service;
public MyThreadB(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.print(new Object());
}
}
package com.java.mul;
public class Service {
public static void print(Object stringParam) {
try {
synchronized (stringParam) {
while(true) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
同步代码块synchronized(class2)对class2上锁之后,其他线程只能以同步的方式调用class2中的静态同步方法。
只要对象不变,即使对象的属性被改变,运行结果也是同步的。