private int i;
@Override
public void run() {
for(i = 0; i < 50; i ++){
System.out.println(this.getName() + "" + i);
}
}
public static void main(String[] args){
FirstThread ft = new FirstThread();
for(int i =0; i < 100;i ++){
System.out.println(Thread.currentThread().getName() + "" + i);
if(i == 20) {
ft.run();
}
}
}
}
private int i;
public void run() {
for(i = 0; i < 50; i ++){
System.out.println(Thread.currentThread().getName()+ "" + i);
}
}
public static void main(String[] args){
FirstThread ft = new FirstThread();
for(int i =0; i < 100;i ++){
System.out.println(Thread.currentThread().getName() + "" + i);
if(i == 20) {
ft.run();
}
}
}
}
Callable
接口提供了一个call()
方法可以作为线程执行体,call()
方法有返回值且可以声明抛出异常Future
接口来代表Callable
接口里call()
方法的返回值,并为Future
接口提供了一个FutureTask
实现类Future
接口定义的方法:试图取消该Future里关联的Callable任务
public class CallableDemo {
public static void main(String[] args){
FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
int i = 0;
for( ; i < 100; i++){
System.out.println(i);
}
return i;
});
new Thread(task).start();
try {
System.out.println(task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
Runnable
和Callable
优劣势:
Runnable
、Callable
接口,还可以继承其他类target
对象,所以非常适合多个相同线程来处理同一份资源的情况Thread.currentThread()
Thread
优劣势:
Thread
类,所以不能再继承其他父类this
使用new
语句仅仅由Java虚拟机为其分配内存,并没有表现出任何线程的动态特征run
方法,则只会有MainActivity
,而且不能通过getName
获得当前执行线程的名字,而需用Thread.currentThread().getName()
run
方法后,该线程已经不再处于新建状态sleep()
或yield()
方法才会放弃所占用的资源——即必须线程主动放弃所占用的资源线程状态转换图
isAlive()
IllegalThreadStateException
异常MainActivity
调用了A.join()
,则MainActivity
被阻塞,A线程执行完后MainActivity
才执行public class DaemonThread extends Thread {
@Override
public void run() {
for(int i = 0; i< 1000; i++){
System.out.println("DaemonActivity" + i);
}
}
public static void main(String[] args){
DaemonThread thread = new DaemonThread();
thread.setDaemon(true);
thread.start();
for(int i = 0; i < 10; i ++ ){
System.out.println("MainActivity" + i);
}
}
}
运行结果
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
sleep
方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程优先级;但yield
方法只会给优先级相同或更高的线程sleep
方法将转入阻塞状态,直到经过阻塞时间才会转入就绪;yield
强制当前线程转入就绪状态sleep
方法抛出了InterruptedException
,yield方法没抛出异常setPriority
和getPriority
方法来设置和返回指定线程的优先级run()
方法不具有同步安全性sychronized(obj)
中obj
就是共享资源synchronized
来修饰某个方法this
public class DaemonThread extends Thread {
static int balance = 100;
int drawAmount;
String name;
public DaemonThread(int drawAmount, String name){
this.drawAmount = drawAmount;
this.name = name;
}
@Override
public void run() {
this.draw(drawAmount);
}
public synchronized void draw(int amount){
if(balance >= amount){
System.out.println(this.name + "取出了" + amount);
try{
Thread.sleep(1);
} catch (InterruptedException e){
e.printStackTrace();
}
balance -= amount;
System.out.println("\t余额为" + balance);
} else{
System.out.println(this.name + "取现失败");
}
}
public static void main(String[] args){
new DaemonThread(50, "A").start();
new DaemonThread(100, "B").start();
}
}
下列情况下,线程会释放对同步监视器的锁定
wait()
方法下列情况下不会释放:
Thread.sleep()
Thread.yield()
方法suspend
方法加锁
A等B,B等A
导致当前线程等待,直到其他线程调用该同步监视器的notify()或notifyAll()方法
wait()
必须在加锁的情况下执行wait
,notify
,notifyAll()
来进行线程通信Lock
对象,Java提供Condition
保证线程协调Condition
方法如下导致当前线程等待,直到其他线程调用该同步监视器的signal()或signalAll()方法
BlockingQueue
放入元素时,如果该队列已满,则该线程被阻塞;当消费者线程试图从BlockingQueue
取出元素时,如果该队列已空,则该线程被阻塞尝试把E元素放入BlockingQueue
public class BlockingQueueThread extends Thread {
private BlockingQueue<String> bq;
public BlockingQueueThread(BlockingQueue<String> bq){
this.bq = bq;
}
@Override
public void run() {
String[] strColl = new String[]{
"Java",
"Kotlin",
"JavaScript"
};
for(int i = 0; i < 1000; i ++){
try {
System.out.println(getName() + "开始动工" + i);
bq.put(strColl[i % 3]);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getName() + "工作结束");
}
public static void main(String[] args){
BlockingQueue<String> bq = new ArrayBlockingQueue<>(5);
new BlockingQueueThread(bq).start();
}
}
结果展示
可以看到,当Thread-0运行到第6次时就已经被阻塞,不能往里添加内容
ThreadGroup
表示线程组,可以对一批线程进行分类管理ThreadGroup
方法返回线程组中活动线程的数目
Runnable
对象或Callable
对象传给线程池,线程池就会启动一个空闲线程来执行他们Executors
工厂类来生产线程池public class ThreadPoolTest {
public static void main(String[] args){
ExecutorService pool = Executors.newFixedThreadPool(2);
java.lang.Runnable target = () -> {
for (int i = 0; i < 100 ; i ++){
System.out.println(Thread.currentThread().getName() + "的i为" +i);
}
};
pool.submit(target);
pool.submit(target);
pool.shutdown();
}
}
结果展示
ForkJoinPool
是ExecutorService
的实现类public class PrintTask extends RecursiveAction {
public static int THREADSH_HOLD = 50;
private int start;
private int end;
public PrintTask(int start, int end){
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if(end - start < THREADSH_HOLD){
for(int i = start; i < end; i ++){
System.out.println(Thread.currentThread().getName() + "的i为" + i);
}
} else {
PrintTask left = new PrintTask(start, (start + end) / 2);
PrintTask right = new PrintTask((start + end) / 2 , end);
left.fork();
right.fork();
}
}
public static void main(String[] args) throws InterruptedException {
PrintTask printTask = new PrintTask(0 , 300);
ForkJoinPool pool = new ForkJoinPool();
pool.submit(printTask);
pool.awaitTermination(2, TimeUnit.SECONDS);
pool.shutdown();
}
}