目录
一、Java中的多线程
1.通过创建实现Runnable接口的类
步骤:
a.创建一个实现了Runnable接口的类
b.重写接口的run()方法
c.实例化实现了Runnable的类
d.实例化Thread的对象,并将c中的类作为构造函数的参数
e.start();
// Runnable
class MyTarget implements Runnable{
private int num = 10;
@Override
public void run() {
while(true){
if(num > 0){
System.out.println(Thread.currentThread().getName() + "---" + num);
num --;
}else break;
}
}
}
public class Main {
public static void main(String[] args) {
MyTarget tar = new MyTarget();
Thread t1 = new Thread(tar);
Thread t2 = new Thread(tar);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
new Thread(tar).start();//匿名类也可创建线程
}
}
/*
Thread-2---10
Thread-2---9
Thread-2---8
线程1---10
线程2---10
线程1---6
Thread-2---7
线程1---4
线程2---5
线程1---2
Thread-2---3
线程2---1*/
2.通过创建继承Thread的类
步骤:
a.创建一个继承了Thread的类
b.重写接口的run()方法(Thread也实现了Runnable接口)
c.实例化类
d.start();
//extends
class thread extends Thread{
private static int num = 10;
@Override
public void run() {
while(true){
if(num > 0){
System.out.println(Thread.currentThread().getName() + "---" + num);
num --;
}else break;
}
}
}
public class Main {
public static void main(String[] args) {
thread t1 = new thread();
thread t2 = new thread();
t1.setName("线程1");
t2.setName("线程2");
new Thread("线程3"){//匿名类创建线程
@Override
public void run() {
for(int i = 0; i < 10; i ++){
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}.start();
t1.start();
t2.start();
}
}
/*线程1---10
线程1---9
线程1---8
线程1---7
线程3---0
线程3---1
线程2---10
线程3---2
线程1---6
线程1---4
线程1---3
线程1---2
线程3---3
线程2---5
线程3---4
线程3---5
线程3---6
线程1---1
线程3---7
线程3---8
线程3---9*/
3.创建实现Callable接口的类
a.创建一个实现Callable的实现类
b.实现call方法,将此线程需要执行的操作声明在call()方法中
c.创建Callable接口实现类的对象
d.将该对象作为参数传递到FutureTask构造器中,创建FutureTask对象
e.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
f.获取Callable中call方法的返回值b
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class NumThread implements Callable {
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 1; i < 100; i++) {
if(i % 2 == 0){
System.out.println(i);
sum += i;
}
}
return sum;
}
}
public class Call {
public static void main(String[] args) {
NumThread numThread = new NumThread();
FutureTask futureTask = new FutureTask(numThread);
new Thread(futureTask).start();
try {
Object sum = futureTask.get();
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
4.使用线程池
a.提供指定线程数量(比如10个)的线程池ExecutorService service = Exectors.newFixedThreaPool(10);
b.执行指定的线程操作。需要提供实现Runnable接口或Callable接口实现类的对象
service.execute(Runnable)/service.submit(Callable)
c.关闭连接池
service.shutdown()
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class NumberThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i % 2 == 0){
System.out.println(i);
}
}
}
}
public class ThreadPoll {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new NumberThread());
service.shutdown();
//service.submit();
}
}
二、 多线程安全问题的解决
多线程的安全问题多由线程操作共享数据导致。
1.sychronized同步机制
注意:确保是同一个锁
①代码块
synchronized(同步监视器){
需要被同步的代码:操作共享数据的代码
}
同步监视器:锁,多个线程必须要共用同一把锁,任何类的一个对象都可以充当锁.
使用实现接口的方式中可以用this充当锁
在继承方式中可以使用*.class充当锁(非必要)
// An highlighted block
class MyTarget implements Runnable{
private int num = 10;
@Override
public void run() {
while(true){
synchronized(this){
if(num > 0){
System.out.println(Thread.currentThread().getName() + "---" + num);
num --;
}else break;
}
}
}
}
public class blog {
public static void main(String[] args) {
MyTarget tar = new MyTarget();
Thread t1 = new Thread(tar);
Thread t2 = new Thread(tar);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
new Thread(tar).start();
}
}
class thread extends Thread{
private static int num = 10;
@Override
public void run() {
while(true){
synchronized(thread.class){
if(num > 0){
System.out.println(Thread.currentThread().getName() + "---" + num);
num --;
}else break;
}
}
}
}
public class Main {
public static void main(String[] args) {
thread t1 = new thread();
thread t2 = new thread();
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
②方法
实现接口方法:
方法名前加synchronized如果操作共享数据的代码完整的声明在一个方法中,可以使用同步方法解决线程安全问题 同步监视器为this
继承方法:
再加static此时同步监视器为*.class
class MyTarget implements Runnable{
private static boolean flag = true;
private int num = 10;
private synchronized void show(){
if(num > 0){
System.out.println(Thread.currentThread().getName() + "---" + num);
num --;
if(num <= 0) flag = false;
}
}
@Override
public void run() {
while(flag){
show();
}
}
}
public class Main {
public static void main(String[] args) {
MyTarget tar = new MyTarget();
Thread t1 = new Thread(tar);
Thread t2 = new Thread(tar);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
new Thread(tar).start();
}
}
class thread extends Thread{
private static boolean flag = true;
private static int num = 1000;
private static synchronized void show(){
if(num > 0){
System.out.println(Thread.currentThread().getName() + "---" + num);
num --;
if(num <= 0) flag = false;
}
}
@Override
public void run() {
while(flag){
show();
}
}
}
public class Main {
public static void main(String[] args) {
thread t1 = new thread();
thread t2 = new thread();
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
2.Lock锁
a创建ReentrantLock类(参数类型boolean,true实现先进先出,默认为false)
b.在需要同步的代码块上使用try…finally结构
c.try里调用lock();
d.finally里调用unlock();
import java.util.concurrent.locks.ReentrantLock;
class Win implements Runnable{
private int ticket = 100;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while(true){
try{
lock.lock();
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + "NO." + ticket);
ticket --;
}else break;
}finally{
lock.unlock();
}
}
}
}
public class LockTest {
public static void main(String[] args) {
Win w = new Win();
new Thread(w).start();
new Thread(w).start();
new Thread(w).start();
}
}