参考安卓进阶之光第四章
问题:sleep(),wait(),join()的区别和联系
顺便提一下yield:将线程转为就绪状态,且只会让优先级相同或者更高的线程有执行机会;
问题:run和start的区别
1.继承Thread类
Thread实现了Runnable接口的一个实例
调用start()只是使线程变为可运行态,并不一定立即地执行多线程的代码,什么时候运行是由操作系统决定的;
public class TestThread extends Thread{
@Override
public void run() {
super.run();
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
Thread thread = new TestThread();
thread.start();
}
}
2.实现Runnable接口
public class TestThread1 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
TestThread1 testThread1 = new TestThread1();
Thread thread = new Thread(testThread1);
thread.start();
}
}
3.实现Callable接口,重写call()方法
Callable接口实际属于Executor框架中的功能类,比runnable提供了更强大的功能:
public class TestThread2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyTestCallable myTestCallable = new MyTestCallable();
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(myTestCallable);
System.out.println(future.get());
}
public static class MyTestCallable implements Callable{
@Override
public Object call() throws Exception {
return Thread.currentThread().getName();
}
}
}
interrupt方法可以用来请求中断线程,调用interrupt方法时,线程的中断标志位将被标为true,线程会不断地检测这个标志位
使用中断来终止线程
public class StopThread {
public static void main(String[] args) throws InterruptedException {
MyRunner myRunner = new MyRunner();
Thread thread = new Thread(myRunner,"mythread");
thread.start();
//让主线程睡10ms,使子线程感知中断
TimeUnit.MILLISECONDS.sleep(10);
thread.interrupt();
}
public static class MyRunner implements Runnable{
private long i;
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()){
i++;
System.out.println("i=" + i + Thread.currentThread().getName() );
}
System.out.println("stop");
}
}
}
也可以采用boolean变量控制是否需要停止线程
public class StopThread {
public static void main(String[] args) throws InterruptedException {
MyRunner myRunner = new MyRunner();
Thread thread = new Thread(myRunner,"mythread");
thread.start();
//让主线程睡10ms,使子线程感知中断
TimeUnit.MILLISECONDS.sleep(10);
myRunner.cancel();
}
public static class MyRunner implements Runnable{
private long i;
private volatile boolean mark = true;
@Override
public void run() {
while (mark){
i++;
System.out.println("i=" + i + Thread.currentThread().getName() );
}
System.out.println("stop");
}
public void cancel() {
mark = false;
}
}
}
1.重入锁
支持重进入的锁,表示该锁能够支持一个线程对资源的重复加锁,确保任何时刻只有一个线程进入临界区,临界区就是或同一时刻只能有一个任务访问的代码区.一旦一个线程封锁了锁对象,其他任何线程都无法进入Lock语句.把解锁的操作放在finally中是必须的.因为如果在临界区发生了异常,锁无法释放那么其他线程将会永远被阻塞;
条件对象:也叫条件变量,管理那个已经获得了一个锁但是不能做有用工作的线程,因为可能进入临界区后发现,还有某一个条件没有满足;
问题:lock和synchronized的区别:
举栗说明:一个支付宝转账的例子
public class Alipay {
private double[] accounts;
private Lock alipayLock;//重入锁
private Condition condition;//引入条件对象
public Alipay(int n ,double money){
accounts = new double[n];
alipayLock = new ReentrantLock();
condition = alipayLock.newCondition();
for (int i = 0; i < accounts.length; i++) {
accounts[i] = money;
}
}
public void transfer(int from,int to,int amount) throws InterruptedException {
alipayLock.lock();
try {
while (accounts[from]
使用synchronized的写法
public synchronized void transfer(int from, int to, int amount) throws InterruptedException {
while (accounts[from] < amount) {//钱不够转账
wait();
}
accounts[from] -= amount;
accounts[to] += amount;
notifyAll();
}
wait方法将一个线程添加到等待集中
notifyAll等价于condition.signalAll();
声明一个域为volatile,编译器和虚拟记就知道该域可能被另外一个线程并发更新;
java中的堆内存是所有线程的共享的内存区域,存在内存可见性的问题;每个线程都有一个私有的本地内存,本地内存存储了该线程共享变量的副本;
volatile不保证原子性,保证了有序性(在volatile后面的语句不能在它之前执行)
volatile的两种使用场景:
1.用于标志位
2.用于单例模式中的双重检查模式
常用于生产者和消费者的场景,他有两个阻塞场景
BolckQueue的核心方法:
常用的阻塞队列:
实现生产者-消费者模式的两种方法
1.非阻塞队列
public class Test {
private int queueSize = 10;
private PriorityQueue queue = new PriorityQueue<>(queueSize);
public static void main(String[] args) {
Test test = new Test();
Consumer consumer = test.new Consumer();
Producer producer = test.new Producer();
producer.start();
consumer.start();
}
class Consumer extends Thread {
@Override
public void run() {
while (true) {
synchronized (queue) {
while (queue.size() == 0) {
try {
System.out.println("队列空");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
queue.notify();
}
}
//每次移走队首元素
queue.poll();
queue.notify();
}
}
}
}
class Producer extends Thread {
@Override
public void run() {
synchronized (queue) {
while (queue.size() == queueSize) {
try {
System.out.println("队列满了");
queue.wait();
}catch (InterruptedException e){
e.printStackTrace();
queue.notify();
}
}
//每次插入一个元素
queue.offer(1);
queue.notify();
}
}
}
}
2.阻塞队列
public class Test1 {
private int queueSize = 10;
private ArrayBlockingQueue queue =
new ArrayBlockingQueue(queueSize);
public static void main(String[] args) {
Test1 test1 = new Test1();
Consumer consumer = test1.new Consumer();
Producer producer = test1.new Producer();
producer.start();
consumer.start();
}
class Consumer extends Thread{
@Override
public void run() {
while (true){
try {
queue.take();
System.out.println(queue.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Producer extends Thread{
@Override
public void run() {
super.run();
while (true){
try {
queue.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
ThreadPoolExecutor的构造方法参数:
corePoolSize:核心线程数,默认下线程池是空的,任务提交时才会创建线程,如果当前运行的线程数少于corePoolSize,则创建新线程来处理任务
workQueue:任务队列,如果当前线程数大于corePoolSize,则将任务添加到任务队列中,队列是阻塞队列
maximumPoolSize:线程池允许创建的最大线程数,如果任务队列满了并且线程数少于maximumPoolSize,线程池任然会创建新的线程来处理任务
keepAliveTime:非核心线程闲置的超时时间;
TimeUnit:KeepAlive的时间单位
ThreadFactory:线程工厂,一般无需设置
RejectExecutionHandler:饱和策略,任务队列和线程池都满了采取的策略,默认为abordPolicy,并抛出异常
问题:如果最大线程池是128,任务队列容量是10,最多容纳多少任务?
138个,因为首先是线程池和任务队列的关系是线程池从任务队列中去取任务,当核心线程池不满时,就创建新核心线程去处理任务,核心线程池满了,就先把任务放在任务队列中等待处理,任务队列也满了,就在非核心线程池中新建非核心线程去处理任务,非核心线程的存活时间是keepAliveTime,非核心线程池也满了,就是说达到max值了,就执行饱和策略
1.FixedThreadPool
只有核心线程,没有非核心线程
2.CachedThreadPool
没有核心线程,非核心线程是无界的,适合大量的需要立即处理并且耗时较少的任务
3.SingleThreadPool
单个工作的线程,只有一个核心线程,能确保所有任务都在一个线程中按照顺序执行
4.ScheduledThreadPool
定时和周期性任务的线程池
是一个抽象的泛型类,有三个泛型参数,分别是
四个核心方法:
举栗说明:参考https://blog.csdn.net/yixingling/article/details/79517048
public class AsyncTaskActivity extends AppCompatActivity {
private EditText et;
private TextView tv;
private Button bt;
private int time = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
bindID();
}
private void bindID() {
et = findViewById(R.id.et_asyc);
tv = findViewById(R.id.tv_asyc);
bt = findViewById(R.id.bt_asyc);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!TextUtils.isEmpty(et.getText())) {
time = Integer.parseInt(et.getText().toString());
new MyTask().execute(time);
}else {
Toast.makeText(AsyncTaskActivity.this, "请输入起始值", Toast.LENGTH_SHORT).show();
}
}
});
}
@SuppressLint("SetTextI18n")
class MyTask extends AsyncTask{
@Override
protected String doInBackground(Integer... integers) {
for (int i=integers[0];i>=0;i--){
try {
Thread.sleep(1000);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "计时结束";
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
tv.setText(values[0]+"");
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
tv.setText(s);
}
}
}
举栗:模拟下载
public class AsyncTaskActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn1;
private Button btn2;
private ProgressBar pro1;
private ProgressBar pro2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
bindID();
}
private void bindID() {
btn1 = findViewById(R.id.bt1);
btn2 = findViewById(R.id.bt2);
pro1 = findViewById(R.id.pb_asyc);
pro2 = findViewById(R.id.pb2_asyc);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bt1:
DownloadTask downloadTask1 = new DownloadTask();
//执行executeOnExecuter()方法线程并行运行,不过同一时间只能启动五个线程
downloadTask1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 1);
btn1.setText("下载中...");
btn1.setEnabled(false);//按钮变为不可按
break;
case R.id.bt2:
DownloadTask downloadTask2 = new DownloadTask();
downloadTask2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 2);
btn2.setText("下载中...");
btn2.setEnabled(false);
break;
default:
break;
}
}
class DownloadTask extends AsyncTask {
@Override
protected Integer doInBackground(Integer... integers) {
for (int i=0;i<=10;i++){
try {
Thread.sleep(1000);
publishProgress(integers[0],i);//哪一个,值,注意这里的参数是[0]
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return integers[0]; //把下载的第几个传过去
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
switch (values[0]){
case 1:
pro1.setProgress(values[1]*10);
break;
case 2:
pro2.setProgress(values[1]*10);
break;
}
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
switch (integer){
case 1:
btn1.setText("下载完成");
btn1.setEnabled(true);
break;
case 2:
btn2.setText("下载完成");
btn2.setEnabled(true);
break;
}
}
}
}